<?php
if (session_status() === PHP_SESSION_NONE) { session_start(); }
error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);

if (!defined('PAZAR_LEGACY_ROOTPATH')) define('PAZAR_LEGACY_ROOTPATH', dirname(__DIR__, 2) . DIRECTORY_SEPARATOR);
if (!defined('ROOTPATH')) define('ROOTPATH', PAZAR_LEGACY_ROOTPATH);
if (!defined('APPPATH')) define('APPPATH', ROOTPATH . 'app' . DIRECTORY_SEPARATOR);
if (!defined('VIEWPATH')) define('VIEWPATH', APPPATH . 'Views' . DIRECTORY_SEPARATOR);
if (!defined('PUBLICPATH')) define('PUBLICPATH', ROOTPATH . 'public' . DIRECTORY_SEPARATOR);

class AppObj { public function getLocale(){ return $GLOBALS['locale'] ?? 'id'; } }
class UrlObj { public function current(){ return current_url(); } }
class Route { public static function currentRouteName(){ return $GLOBALS['routeName'] ?? 'id.index'; } }
function app(){ return new AppObj(); }
function url($path=null){ if($path===null) return new UrlObj(); return base_url($path); }
function request_path_without_base(){
    $requestPath = trim(parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH), '/');
    $basePrefix = app_base_path();
    if ($basePrefix !== '' && ($requestPath === $basePrefix || str_starts_with($requestPath, $basePrefix.'/'))) {
        return trim(substr($requestPath, strlen($basePrefix)), '/');
    }
    return $requestPath;
}
if (!function_exists('current_url')) { function current_url(){ return base_url(request_path_without_base()); } }
function app_base_path(){
    $script = str_replace('\\','/', $_SERVER['SCRIPT_NAME'] ?? '');
    $dir = trim(dirname($script), '/');
    if ($dir === '.') $dir = '';
    // Kalau file yang berjalan berada di folder public, base aplikasi adalah parent-nya.
    if ($dir !== '' && basename($dir) === 'public') {
        $dir = trim(dirname('/'.$dir), '/');
    }
    return $dir;
}
function detected_base_url(){
    $scheme=(!empty($_SERVER['HTTPS'])&&$_SERVER['HTTPS']!=='off')?'https':'http';
    $host=$_SERVER['HTTP_HOST']??'localhost';
    $base=app_base_path();
    return $scheme.'://'.$host.($base?'/'.$base:'').'/';
}
if (!function_exists('base_url')) { function base_url($path=''){
    $configured = envv('app.baseURL', '');
    $host = $_SERVER['HTTP_HOST'] ?? '';
    // Di localhost/XAMPP, jangan pakai baseURL domain production dari .env.
    if ($configured && !preg_match('~^(localhost|127\.0\.0\.1)(:|$)~', $host)) {
        $base = $configured;
    } else {
        $base = detected_base_url();
    }
    return rtrim($base,'/').'/'.ltrim($path,'/');
} }
function asset($path){ return base_url($path); }
function e($v){ return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8'); }



function pazar_cache_dir(){
    $dir = ROOTPATH.'writable'.DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR.'pazar-pages'.DIRECTORY_SEPARATOR;
    if(!is_dir($dir)) @mkdir($dir,0775,true);
    return $dir;
}
function pazar_frontend_cache_enabled(){ return envv('pazar.frontendCache','true') !== 'false'; }
function pazar_cache_ttl(){ return max(60, (int)envv('pazar.frontendCacheTTL','900')); }
function pazar_cache_key(){
    $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
    $uri = $_SERVER['REQUEST_URI'] ?? '/';
    $theme = $_COOKIE['theme'] ?? 'light';
    return sha1($host.'|'.$uri.'|'.$theme);
}
function pazar_is_cacheable_request(){
    if(!pazar_frontend_cache_enabled()) return false;
    if(($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'GET') return false;
    $path = request_path_without_base();
    if($path === 'theme/toggle' || str_starts_with($path,'language/') || str_starts_with($path,'panel-pazar-seasonings')) return false;
    if(isset($_GET['nocache']) || isset($_GET['preview'])) return false;
    return true;
}
function pazar_cache_file(){ return pazar_cache_dir().pazar_cache_key().'.html'; }
function pazar_cache_try_serve(){
    if(!pazar_is_cacheable_request()) return;
    $file=pazar_cache_file();
    if(is_file($file) && (time()-filemtime($file) <= pazar_cache_ttl())){
        header('X-Pazar-Cache: HIT');
        header('Cache-Control: public, max-age=300');
        readfile($file); exit;
    }
    header('X-Pazar-Cache: MISS');
    ob_start();
    register_shutdown_function(function(){
        if(!pazar_is_cacheable_request()) return;
        $status = function_exists('http_response_code') ? http_response_code() : 200;
        if($status !== 200) return;
        $html = ob_get_contents();
        if(!is_string($html) || trim($html)==='' || stripos($html,'<html')===false) return;
        @file_put_contents(pazar_cache_file(), $html, LOCK_EX);
    });
}
function pazar_clear_frontend_cache(){
    $dir=pazar_cache_dir();
    foreach(glob($dir.'*.html') ?: [] as $file){ @unlink($file); }
}
function pazar_optimize_frontend_html($html){
    if(!is_string($html) || stripos($html,'<html')===false) return $html;
    $logo = asset('img/Web/Logo.webp');
    if(stripos($html,'rel="preload" href="'.$logo.'"')===false){
        $preloads = '<link rel="preload" href="'.$logo.'" as="image" fetchpriority="high">';
        if(preg_match('~<img\s+[^>]*src=["\']([^"\']+)["\'][^>]*>~i',$html,$m)){
            $first=$m[1];
            if($first && $first!==$logo && !str_contains($first,'data:')) $preloads .= '<link rel="preload" href="'.e($first).'" as="image" fetchpriority="high">';
        }
        $html = preg_replace('~</head>~i', $preloads."\n</head>", $html, 1);
    }
    $imgIndex=0;
    $html = preg_replace_callback('~<img\b([^>]*)>~i', function($m) use (&$imgIndex){
        $tag=$m[0]; $attrs=$m[1]; $imgIndex++;
        if(stripos($attrs,'loading=')===false){ $tag = rtrim(substr($tag,0,-1)).($imgIndex<=2?' loading="eager" fetchpriority="high"':' loading="lazy"').'>'; }
        if(stripos($attrs,'decoding=')===false){ $tag = rtrim(substr($tag,0,-1)).' decoding="async">'; }
        return $tag;
    }, $html);
    $html = preg_replace_callback('~<iframe\b([^>]*)>~i', function($m){
        $tag=$m[0]; $attrs=$m[1];
        if(stripos($attrs,'loading=')===false) $tag = rtrim(substr($tag,0,-1)).' loading="lazy">';
        return $tag;
    }, $html);
    return $html;
}

function pazar_clean_text($text){
    $text = html_entity_decode(strip_tags((string)$text), ENT_QUOTES, 'UTF-8');
    return trim(preg_replace('/\s+/u',' ', $text));
}
function pazar_looks_indonesian($text){
    $plain = mb_strtolower(pazar_clean_text($text), 'UTF-8');
    if($plain==='') return false;
    $markers = [' yang ',' dan ',' dengan ',' untuk ',' dari ',' dalam ',' pada ',' sebagai ',' tanpa ',' perlu ',' produk ',' bumbu ',' rempah ',' sambal ',' resep ',' karir ',' lowongan ',' perusahaan ',' kami ',' kualitas ',' halal ',' pelanggan ',' hidangan ',' masakan ',' dapur ',' menakar ',' meracik ',' berbahan ',' digunakan ',' dibuat ',' diproses ',' terbaik ',' pilihan ',' cocok ',' aman ',' praktis ',' gurih ',' pedas ',' rasa ',' cita rasa '];
    $hay = ' '.$plain.' ';
    $score = 0;
    foreach($markers as $m){ if(strpos($hay,$m)!==false) $score++; }
    return $score >= 1;
}
function pazar_restore_case($source, $target){
    if($source === mb_strtoupper($source, 'UTF-8')) return mb_strtoupper($target, 'UTF-8');
    $first = mb_substr($source,0,1,'UTF-8');
    if($first === mb_strtoupper($first,'UTF-8')) return mb_strtoupper(mb_substr($target,0,1,'UTF-8'),'UTF-8').mb_substr($target,1,null,'UTF-8');
    return $target;
}
function pazar_translation_provider(){
    return strtolower(trim(envv('translation.provider', 'gemini')));
}

function pazar_gemini_api_key(){
    return trim(envv('gemini.api_key', '') ?: envv('GEMINI_API_KEY', ''));
}
function pazar_gemini_model(){
    return trim(envv('gemini.model', 'gemini-2.5-flash'));
}
function pazar_gemini_fallback_models(){
    $raw = trim(envv('gemini.fallback_models', 'gemini-3.1-flash-lite-preview,gemini-2.5-flash-lite'));
    if($raw === '') return [];
    $items = array_filter(array_map('trim', explode(',', $raw)));
    return array_values(array_unique($items));
}
function pazar_gemini_candidate_models(){
    $models = array_merge([pazar_gemini_model()], pazar_gemini_fallback_models());
    return array_values(array_unique(array_filter($models)));
}
function pazar_gemini_retry_count(){
    $n = (int)envv('gemini.retry', '3');
    return max(1, min(5, $n));
}
function pazar_http_post_json($url, $payload, $headers=[], $timeout=60){
    $body = json_encode($payload, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
    $headers = array_merge(['Content-Type: application/json'], $headers);
    if(function_exists('curl_init')){
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_POSTFIELDS => $body,
            CURLOPT_TIMEOUT => $timeout,
            CURLOPT_CONNECTTIMEOUT => 15,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
        ]);
        $response = curl_exec($ch);
        $err = curl_error($ch);
        $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        return [$code, $response, $err];
    }
    $headerText = implode("\r\n", $headers);
    $context = stream_context_create(['http'=>[
        'method'=>'POST',
        'header'=>$headerText,
        'content'=>$body,
        'timeout'=>$timeout,
        'ignore_errors'=>true,
    ], 'ssl'=>[
        'verify_peer'=>false,
        'verify_peer_name'=>false,
    ]]);
    $response = @file_get_contents($url, false, $context);
    $code = 0;
    if(isset($http_response_header) && is_array($http_response_header)){
        foreach($http_response_header as $h){ if(preg_match('~HTTP/\S+\s+(\d+)~', $h, $m)){ $code=(int)$m[1]; break; } }
    }
    $err = $response===false ? 'cURL tidak aktif dan file_get_contents gagal menghubungi API.' : '';
    return [$code, $response, $err];
}
function pazar_clean_ai_translation($translated, $original=''){
    $translated = trim((string)$translated);
    $translated = preg_replace('~^```(?:text|html)?\s*|\s*```$~iu', '', $translated);
    $translated = preg_replace('~^\s*(Translation|English|Output)\s*:\s*~iu', '', $translated);
    $translated = trim($translated, " \t\n\r\0\x0B\"'");
    if($translated === '' || mb_strlen($translated,'UTF-8') < 1) return '';
    return $translated;
}
function pazar_gemini_translate_to_en($text){
    $original = (string)$text;
    if(trim($original)==='') return $original;
    $apiKey = pazar_gemini_api_key();
    if($apiKey === ''){
        $GLOBALS['pazar_translate_last_error'] = 'GEMINI API key belum diisi di .env.';
        return null;
    }

    $prompt = "Translate Indonesian website CMS content into natural, polished English for Pazar Seasonings, a food seasoning company.\n".
        "Rules:\n".
        "- Return ONLY the English translation, without notes, labels, quotes, markdown, or the original Indonesian text.\n".
        "- Translate the whole text naturally; do not leave Indonesian words mixed in unless they are proper names, product/brand names, certification names, or Indonesian dish names commonly kept in English.\n".
        "- Preserve brand/entity names exactly: Pazar, Pazar Seasonings, PT Pristine Prima Lestari, MUI, NKV, BRCGS, Halal.\n".
        "- Preserve HTML tags, URLs, emails, numbers, emojis, punctuation style, and line breaks.\n".
        "- Use clear marketing-friendly English suitable for company profile, products, recipes, SEO, and careers.\n".
        "- Do not translate word-by-word. Rewrite naturally when needed.\n".
        "- Examples: 'Hemat Waktu & Tenaga' => 'Save Time & Effort'; 'Tanpa perlu menakar dan meracik, makanan lezat siap lebih cepat' => 'No need to measure and mix; delicious meals are ready faster.'\n\n".
        "Indonesian text:\n".$original;

    $payload = [
        'contents' => [[ 'role' => 'user', 'parts' => [[ 'text' => $prompt ]] ]],
        'generationConfig' => [
            'temperature' => 0.1,
            'topP' => 0.8,
            'maxOutputTokens' => 8192,
            'responseMimeType' => 'text/plain',
        ],
    ];

    $errors = [];
    foreach(pazar_gemini_candidate_models() as $model){
        $cached = pazar_translate_cache_get('gemini_v13', $model, $original);
        if($cached !== null && trim((string)$cached) !== ''){
            $GLOBALS['pazar_translate_last_provider'] = 'gemini-cache:'.$model;
            $GLOBALS['pazar_translate_last_error'] = '';
            return $cached;
        }
        $endpoint = 'https://generativelanguage.googleapis.com/v1beta/models/'.rawurlencode($model).':generateContent';
        $maxTry = pazar_gemini_retry_count();
        for($attempt=1; $attempt <= $maxTry; $attempt++){
            [$code, $response, $err] = pazar_http_post_json($endpoint, $payload, ['x-goog-api-key: '.$apiKey], 70);
            if($response !== false && $code >= 200 && $code < 300){
                $json = json_decode($response, true);
                $translated = '';
                if(isset($json['candidates'][0]['content']['parts']) && is_array($json['candidates'][0]['content']['parts'])){
                    foreach($json['candidates'][0]['content']['parts'] as $part){ if(isset($part['text'])) $translated .= $part['text']; }
                }
                if($translated === '' && isset($json['candidates'][0]['content']['parts'][0]['text'])) $translated = $json['candidates'][0]['content']['parts'][0]['text'];
                $translated = pazar_clean_ai_translation($translated, $original);
                if($translated !== ''){
                    pazar_translate_cache_set('gemini_v13', $model, $original, $translated);
                    $GLOBALS['pazar_translate_last_provider'] = 'gemini:'.$model;
                    $GLOBALS['pazar_translate_last_error'] = '';
                    return $translated;
                }
                $errors[] = $model.' attempt '.$attempt.': response kosong / tidak terbaca';
                break;
            }
            $shortResponse = substr((string)$response, 0, 700);
            $message = $err ?: ('HTTP '.$code.' - '.$shortResponse);
            $errors[] = $model.' attempt '.$attempt.': '.$message;
            // 503/429 biasanya overload/limit sementara. Coba ulang sebentar, lalu pindah model fallback.
            if(in_array($code, [429, 500, 502, 503, 504], true) && $attempt < $maxTry){
                usleep((250000 * $attempt) + random_int(0, 250000));
                continue;
            }
            break;
        }
    }
    $msg = implode(' | ', array_slice($errors, -6));
    $GLOBALS['pazar_translate_last_error'] = $msg ?: 'Gemini gagal dipanggil.';
    @file_put_contents(ROOTPATH.'writable'.DIRECTORY_SEPARATOR.'logs'.DIRECTORY_SEPARATOR.'pazar_gemini_error.log', date('c').' '.$GLOBALS['pazar_translate_last_error']."\n", FILE_APPEND);
    return null;
}

function pazar_openai_api_key(){
    return trim(envv('openai.api_key', '') ?: envv('OPENAI_API_KEY', ''));
}
function pazar_openai_model(){
    return trim(envv('openai.model', 'gpt-5.4-mini'));
}
function pazar_translate_cache_path(){
    return ROOTPATH.'writable'.DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR.'pazar_translate_cache.json';
}
function pazar_translate_cache_get($provider, $model, $text){
    $path = pazar_translate_cache_path();
    if(!is_file($path)) return null;
    $cache = json_decode(@file_get_contents($path) ?: '{}', true);
    if(!is_array($cache)) return null;
    $key = sha1($provider.'|'.$model.'|id-en|'.$text);
    return $cache[$key]['value'] ?? null;
}
function pazar_translate_cache_set($provider, $model, $text, $value){
    $dir = dirname(pazar_translate_cache_path());
    if(!is_dir($dir)) @mkdir($dir, 0775, true);
    $path = pazar_translate_cache_path();
    $cache = [];
    if(is_file($path)){
        $cache = json_decode(@file_get_contents($path) ?: '{}', true);
        if(!is_array($cache)) $cache = [];
    }
    $key = sha1($provider.'|'.$model.'|id-en|'.$text);
    $cache[$key] = ['value'=>$value, 'time'=>date('c')];
    if(count($cache) > 2500){
        uasort($cache, fn($a,$b)=>strcmp($b['time'] ?? '', $a['time'] ?? ''));
        $cache = array_slice($cache, 0, 2000, true);
    }
    @file_put_contents($path, json_encode($cache, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT));
}
function pazar_openai_translate_to_en($text){
    $original = (string)$text;
    if(trim($original)==='') return $original;
    $apiKey = pazar_openai_api_key();
    if($apiKey === ''){
        $GLOBALS['pazar_translate_last_error'] = 'OPENAI API key belum diisi di .env.';
        return null;
    }
    $model = pazar_openai_model();
    $cached = pazar_translate_cache_get('openai', $model, $original);
    if($cached !== null && trim((string)$cached) !== '') return $cached;

    $system = "You are a professional Indonesian-to-English translator for Pazar Seasonings, a food/seasoning company. Translate naturally for a company profile website, product pages, recipes, SEO text, and career pages. Preserve brand names such as Pazar, Pazar Seasonings, PT Pristine Prima Lestari, MUI, NKV, BRCGS. Preserve HTML tags, URLs, emails, numbers, emojis, punctuation style, and line breaks. Do not add explanations. Return only the translated English text.";
    $user = "Translate this Indonesian content to natural English. Keep any existing HTML intact.\n\n".$original;
    $payload = [
        'model' => $model,
        'messages' => [
            ['role'=>'system','content'=>$system],
            ['role'=>'user','content'=>$user],
        ],
        'temperature' => 0.2,
    ];
    $ch = curl_init('https://api.openai.com/v1/chat/completions');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/json',
            'Authorization: Bearer '.$apiKey,
        ],
        CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
        CURLOPT_TIMEOUT => 45,
        CURLOPT_CONNECTTIMEOUT => 15,
    ]);
    $response = curl_exec($ch);
    $err = curl_error($ch);
    $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if($response === false || $code < 200 || $code >= 300){
        $GLOBALS['pazar_translate_last_error'] = $err ?: ('OpenAI HTTP '.$code.' - '.substr((string)$response, 0, 500));
        return null;
    }
    $json = json_decode($response, true);
    $translated = trim((string)($json['choices'][0]['message']['content'] ?? ''));
    if($translated === ''){
        $GLOBALS['pazar_translate_last_error'] = 'OpenAI response kosong / tidak terbaca.';
        return null;
    }
    pazar_translate_cache_set('openai', $model, $original, $translated);
    return $translated;
}
function pazar_translate_to_en($text, $force=true){
    $original = (string)$text;
    if(trim($original)==='') return $original;
    if(!$force && !pazar_looks_indonesian($original)) return $original;
    $GLOBALS['pazar_translate_last_provider'] = 'local';
    $provider = pazar_translation_provider();
    if($provider === 'gemini'){
        $translated = pazar_gemini_translate_to_en($original);
        if(is_string($translated) && trim($translated) !== '') return $translated;
        if(trim(envv('gemini.allow_local_fallback', '0')) !== '1'){
            $GLOBALS['pazar_translate_last_provider'] = 'gemini-failed-keep-original';
            return null;
        }
        $GLOBALS['pazar_translate_last_provider'] = 'local-fallback';
    }
    if($provider === 'openai'){
        $translated = pazar_openai_translate_to_en($original);
        if(is_string($translated) && trim($translated) !== ''){ $GLOBALS['pazar_translate_last_provider']='openai'; return $translated; }
        $GLOBALS['pazar_translate_last_provider'] = 'local-fallback';
    }
    if($provider === 'off') return $original;
    return pazar_translate_free_to_en($original, $force);
}

function pazar_translate_free_to_en($text, $force=true){
    $original = (string)$text;
    if(trim($original)==='') return $original;
    if(!$force && !pazar_looks_indonesian($original)) return $original;

    // Translator gratis internal v9: kamus frasa panjang + pembersihan mixed language.
    // Fokus untuk konten Pazar Seasonings: company profile, brand, produk, resep, karir, SEO.
    // Tidak memakai API/biaya, menjaga HTML ringan, URL, email, dan angka.
    $html = $original;
    $tokens=[];
    $html = preg_replace_callback('/(<[^>]+>|https?:\/\/[^\s<]+|www\.[^\s<]+|[A-Z0-9._%+\-]+@[A-Z0-9.\-]+\.[A-Z]{2,})/iu', function($m) use (&$tokens){
        $k='@@PZRTOKEN'.count($tokens).'@@'; $tokens[$k]=$m[0]; return $k;
    }, $html);

    $dict = [
        // Brand/entity - jangan diterjemahkan
        'Pazar Seasonings'=>'Pazar Seasonings','Pazar Seasoning'=>'Pazar Seasoning','PAZAR'=>'PAZAR','Pazar'=>'Pazar','PT Pristine Prima Lestari'=>'PT Pristine Prima Lestari','Indonesia'=>'Indonesia','Indonesian'=>'Indonesian','Nusantara'=>'Indonesian Archipelago','HOREKA'=>'HORECA','Horeka'=>'Horeca','MUI'=>'MUI','NKV'=>'NKV','BRCGS'=>'BRCGS',

        // Headline/frasa website
        '#JadiBisaMasak'=>'#NowYouCanCook','Praktis Bersama PAZAR'=>'Practical with PAZAR','Kelezatan setiap hidangan berawal dari bahan dasar berkualitas'=>'The deliciousness of every dish starts with quality ingredients','menghadirkan produk bumbu, rempah dan sambal terbaik'=>'provides the best seasoning, spice, and chili sauce products','memperkaya cita rasa kuliner nusantara maupun dunia'=>'enrich the flavors of Indonesian and international cuisine',
        'Perusahaan Kami'=>'Our Company','Brand Kami'=>'Our Brand','Produk Pazar Seasoning'=>'Pazar Seasoning Products','Resep Pazar Seasoning'=>'Pazar Seasoning Recipes','Info Karir'=>'Career Info','Lowongan'=>'Vacancies','Kenapa Pazar'=>'Why Pazar','Kenapa Pazar?'=>'Why Pazar?','Kategori Produk'=>'Product Category','Produk Spesial'=>'Special Products','Produk Terbaru'=>'Newest Products','Resep Terbaru'=>'Newest Recipes','Lihat Produk'=>'View Products','Lihat Resep'=>'View Recipes','Selengkapnya'=>'Read More','Beli Sekarang'=>'Buy Now','Unduh Katalog'=>'Download Catalog','Kembali'=>'Back','Kembali ke Beranda'=>'Back to Home',
        'Hemat Waktu & Tenaga'=>'Save Time & Effort','Hemat Waktu dan Tenaga'=>'Save Time & Effort','Hemat Waktu'=>'Save Time','Tanpa perlu menakar dan meracik, makanan lezat siap lebih cepat'=>'No need to measure and mix; delicious meals are ready faster','Tanpa perlu menakar dan meracik'=>'No need to measure and mix','Tanpa perlu menakar'=>'No need to measure','makanan lezat siap lebih cepat'=>'delicious meals are ready faster','masakan lezat siap lebih cepat'=>'delicious dishes are ready faster','Kualitas Rempah Asli'=>'Original Quality Spices','Rempah Asli Berkualitas'=>'Quality Authentic Spices','Cocok untuk Semua Kebutuhan'=>'Suitable for All Needs','Terpercaya & Populer'=>'Trusted & Popular','Dipilih oleh ribuan pelanggan'=>'Chosen by thousands of customers','menciptakan hidangan istimewa'=>'create special dishes','Dari rumah hingga bisnis kuliner'=>'From home kitchens to culinary businesses','hasil masakan tetap premium'=>'cooking results remain premium','Terbuat dari rempah pilihan'=>'Made from selected spices','diproses dengan standar terbaik'=>'processed to the highest standards',

        // Produk dan kategori
        'Bumbu Ayam Goreng'=>'Fried Chicken Seasoning','Bumbu Ayam Kalasan'=>'Kalasan Chicken Seasoning','Bumbu Kuah Bakso'=>'Meatball Broth Seasoning','Bumbu Soto Betawi'=>'Betawi Soto Seasoning','Bumbu Soto Lamongan'=>'Lamongan Soto Seasoning','Bumbu Rendang'=>'Rendang Seasoning','Bumbu Rawon'=>'Rawon Seasoning','Bumbu Opor'=>'Opor Seasoning','Bumbu Rica'=>'Rica Seasoning','Bumbu Woku'=>'Woku Seasoning','Bumbu Empal'=>'Empal Seasoning','Bumbu Tom Yam'=>'Tom Yum Seasoning','Bumbu Tomyam'=>'Tom Yum Seasoning','Bumbu Nasi Goreng'=>'Fried Rice Seasoning','Bumbu Instan'=>'Instant Seasoning','Bumbu Tabur'=>'Seasoning Powder','Bumbu Masak'=>'Cooking Seasoning','Tepung Bumbu'=>'Seasoned Flour','Tepung berbumbu'=>'Seasoned Flour','Kondimen'=>'Condiment','Bumbu'=>'Seasoning',
        'Sambal Terasi'=>'Shrimp Paste Chili Sauce','Sambal Bajak'=>'Bajak Chili Sauce','Sambal Bakso'=>'Meatball Chili Sauce','Sambal Hijau'=>'Green Chili Sauce','Sambal'=>'Chili Sauce','Cabai Kering Kasar'=>'Coarse Chili Flakes','Cabai Bubuk Halus'=>'Fine Chili Powder','Cabai Bubuk'=>'Chili Powder','Cabai'=>'Chili','Cabe'=>'Chili','Kunyit Bubuk'=>'Turmeric Powder','Bawang Putih Bubuk'=>'Garlic Powder','Lada Hitam Bubuk Halus'=>'Fine Black Pepper Powder','Lada Hitam Bubuk'=>'Black Pepper Powder','Lada Putih Bubuk'=>'White Pepper Powder','Lada Hitam'=>'Black Pepper','Lada Putih'=>'White Pepper','Kayu Manis Bubuk'=>'Cinnamon Powder','Kayu Manis'=>'Cinnamon','Ngohiong Bubuk'=>'Five-Spice Powder','Ketumbar Bubuk'=>'Coriander Powder','Ketumbar'=>'Coriander','Bawang Goreng'=>'Fried Shallots','Bawang Merah'=>'Shallot','Bawang Putih'=>'Garlic','Bawang'=>'Onion','Rempah-rempah'=>'Spices','Rempah'=>'Spices',

        // Nama makanan
        'Ayam Goreng'=>'Fried Chicken','Ayam Bakar'=>'Grilled Chicken','Ayam Kalasan'=>'Kalasan Chicken','Opor Ayam'=>'Chicken Opor','Soto Betawi'=>'Betawi Soto','Soto Lamongan'=>'Lamongan Soto','Nasi Goreng'=>'Fried Rice','Tom Yam'=>'Tom Yum','Tomyam'=>'Tom Yum','Bakso'=>'Meatball','Rendang'=>'Rendang','Rawon'=>'Rawon','Empal'=>'Empal','Rica-rica'=>'Rica-Rica','Woku'=>'Woku','Gulai'=>'Gulai','Sate'=>'Satay','Siomay'=>'Dumplings','Lumpia'=>'Spring Rolls','Mie'=>'Noodles','Kue'=>'Cake','Sup Ayam'=>'Chicken Soup','Sup'=>'Soup','Soto'=>'Soto','Daging Sapi'=>'Beef','Daging'=>'Meat','Sapi'=>'Beef','Ayam'=>'Chicken','Ikan'=>'Fish','Seafood'=>'Seafood','Nasi'=>'Rice','Sayur'=>'Vegetables','Lalapan'=>'Fresh Vegetables','Kentang'=>'Potato',

        // Company/career/sertifikasi
        'produsen makanan dan minuman halal'=>'halal food and beverage manufacturer','produsen bumbu'=>'seasoning manufacturer','penyedia produk pangan global'=>'global food product provider','sistem keamanan pangan'=>'food safety system','standar keamanan pangan'=>'food safety standards','standar keamanan global'=>'global safety standards','budaya mutu'=>'quality culture','keamanan pangan'=>'food safety','peraturan perundang-undangan yang berlaku'=>'applicable laws and regulations','perbaikan yang berkelanjutan'=>'continuous improvement','kebutuhan dan harapan pelanggan'=>'customer needs and expectations','Sertifikat HALAL MUI'=>'MUI HALAL Certificate','Sertifikat NKV'=>'NKV Certificate','Sertifikat BRCGS'=>'BRCGS Certificate','Sertifikasi Halal'=>'Halal Certification','Keamanan Pangan'=>'Food Safety','Standar Internasional'=>'International Standard','Higiene'=>'Hygiene','Menandakan bahwa'=>'Indicates that','Nomor Kontrol Veteriner'=>'Veterinary Control Number','Kementerian Pertanian'=>'Ministry of Agriculture','hulu ke hilir'=>'upstream to downstream','diakui dunia'=>'recognized worldwide','aman dikonsumsi'=>'safe for consumption','Bergabunglah'=>'Join','bergabunglah'=>'join','Pengalaman'=>'Experience','Departemen'=>'Department','Tanggung Jawab'=>'Responsibilities','Persyaratan'=>'Requirements','Penuh Waktu'=>'Full Time','Paruh Waktu'=>'Part Time','Kontrak'=>'Contract','Magang'=>'Internship','Segera'=>'Urgent',

        // UI/Form/SEO
        'Judul'=>'Title','Deskripsi Singkat'=>'Short Description','Deskripsi'=>'Description','Konten'=>'Content','Isi Lengkap'=>'Full Content','Gambar'=>'Image','Foto'=>'Photo','Status'=>'Status','Aktif'=>'Active','Tidak Aktif'=>'Inactive','Nonaktif'=>'Inactive','Tampilkan'=>'Show','Sembunyikan'=>'Hide','Simpan'=>'Save','Ubah'=>'Edit','Hapus'=>'Delete','Tambah'=>'Add','Cari'=>'Search','Meta Title'=>'Meta Title','Meta Description'=>'Meta Description','Focus Keyword'=>'Focus Keyword',

        // Frasa umum marketing
        'Kami percaya'=>'We believe','kami percaya'=>'we believe','Kami hadir'=>'We are here','kami hadir'=>'we are here','Kami menghadirkan'=>'We deliver','kami menghadirkan'=>'we deliver','Kami menyediakan'=>'We provide','kami menyediakan'=>'we provide','Kami menggunakan'=>'We use','kami menggunakan'=>'we use','Kami berkomitmen'=>'We are committed','kami berkomitmen'=>'we are committed','berkomitmen menghadirkan'=>'is committed to delivering','terus berinovasi'=>'continue to innovate','inovasi berkelanjutan'=>'continuous innovation','tanpa mengurangi'=>'without compromising','cita rasa autentik'=>'authentic flavor','cita rasa khas'=>'distinctive flavor','bercita rasa tinggi'=>'full of flavor','solusi yang aman'=>'safe solutions','solusi praktis'=>'practical solutions','dapur modern'=>'modern kitchen','pengalaman memasak'=>'cooking experience','jadi menyenangkan'=>'more enjoyable','menjadi perusahaan'=>'to become a company','bergerak di bidang'=>'engaged in','bidang usaha produksi'=>'production business field','bertekad menjadi'=>'is determined to become','mencapai tujuan'=>'achieve this goal','menyatakan tekadnya'=>'declare their commitment','menerapkan'=>'implement','melakukan'=>'carry out','memenuhi'=>'meet','mematuhi'=>'comply with','menjamin'=>'ensure','diproses'=>'processed','terjamin'=>'guaranteed','berkualitas tinggi'=>'high quality','berkualitas'=>'quality','terbaik'=>'best','pilihan'=>'selected','asli'=>'authentic','alami'=>'natural','tradisional'=>'traditional','otentik'=>'authentic','khas'=>'special','lezat'=>'delicious','gurih'=>'savory','pedas'=>'spicy','manis'=>'sweet','asam'=>'sour','segar'=>'fresh','aromatik'=>'aromatic','lembut'=>'mild','renyah'=>'crispy','empuk'=>'tender','kaya rasa'=>'rich in flavor','penuh rasa'=>'full of flavor','rasa'=>'taste','aroma'=>'aroma','tekstur'=>'texture','kemasan'=>'packaging','dapur'=>'kitchen','hotel'=>'hotel','restoran'=>'restaurant','katering'=>'catering','keluarga'=>'family','pelanggan'=>'customers','hidangan'=>'dish','masakan'=>'cuisine','makanan'=>'food','minuman'=>'beverage','produk'=>'product','resep'=>'recipe','kategori'=>'category',

        // Bahan dan instruksi resep
        'bahan-bahan'=>'ingredients','bahan'=>'ingredients','cara memasak'=>'cooking steps','cara membuat'=>'how to make','langkah'=>'step','siapkan'=>'prepare','masukkan'=>'add','tambahkan'=>'add','aduk'=>'stir','aduk rata'=>'mix well','goreng'=>'fry','tumis'=>'sauté','rebus'=>'boil','panggang'=>'grill','masak'=>'cook','hingga matang'=>'until cooked','hingga harum'=>'until fragrant','sajikan'=>'serve','taburkan'=>'sprinkle','tuang'=>'pour','iris'=>'slice','haluskan'=>'grind','campurkan'=>'mix','diamkan'=>'let stand','panaskan'=>'heat','secukupnya'=>'to taste','air'=>'water','minyak'=>'oil','garam'=>'salt','gula'=>'sugar','gula merah'=>'brown sugar','santan'=>'coconut milk','susu'=>'milk','kaldu'=>'broth','serai'=>'lemongrass','daun jeruk'=>'lime leaves','daun kemangi'=>'basil leaves','daun salam'=>'bay leaves','lengkuas'=>'galangal','jahe'=>'ginger','pala'=>'nutmeg','cengkeh'=>'cloves','bunga lawang'=>'star anise','adas'=>'fennel','kluwek'=>'kluwek','kecap'=>'soy sauce','tomat'=>'tomato','mie'=>'noodles',

        // Kata sambung. Ditaruh akhir agar frasa panjang diproses dulu.
        'untuk membuat'=>'to make','untuk menghasilkan'=>'to create','untuk menghadirkan'=>'to deliver','untuk menemani'=>'to accompany','siap pakai'=>'ready-to-use','mudah digunakan'=>'easy to use','cocok untuk'=>'suitable for','terbuat dari'=>'made from','berbahan dasar'=>'made from','berasal dari'=>'comes from','dibuat dari'=>'made from','digunakan untuk'=>'used for','digunakan sebagai'=>'used as','dengan standar'=>'with standards','sesuai standar'=>'according to standards','dari rumah'=>'from home','hingga bisnis'=>'to business','dari hulu'=>'from upstream','ke hilir'=>'to downstream','dan'=>'and','atau'=>'or','dengan'=>'with','dari'=>'from','untuk'=>'for','yang'=>'that','ini'=>'this','itu'=>'that','dalam'=>'in','pada'=>'on','ke'=>'to','di'=>'in','sebagai'=>'as','hingga'=>'to','serta'=>'and','karena'=>'because','agar'=>'so that','lebih'=>'more','sangat'=>'very','cocok'=>'suitable','campuran'=>'blend','aneka'=>'various','lainnya'=>'others','semua'=>'all','tanpa'=>'without','perlu'=>'need','menakar'=>'measure','meracik'=>'mix','menciptakan'=>'create','menghasilkan'=>'produce','memberikan'=>'provide','menambah'=>'add','meningkatkan'=>'enhance','memanjakan'=>'delight','lidah'=>'palate','rumah'=>'home','bisnis'=>'business','kuliner'=>'culinary','kuah'=>'broth','bening'=>'clear','kuat'=>'strong','kental'=>'thick','sedikit'=>'slightly','dunia'=>'world','global'=>'global','halal'=>'halal','najis'=>'impure substances','syariat Islam'=>'Islamic law',
    ];
    uksort($dict, fn($a,$b)=>mb_strlen($b,'UTF-8')<=>mb_strlen($a,'UTF-8'));
    foreach($dict as $id=>$en){
        $pattern = '/(?<![\pL\pN])'.preg_quote($id,'/').'(?![\pL\pN])/iu';
        $html = preg_replace_callback($pattern, function($m) use ($en){ return pazar_restore_case($m[0], $en); }, $html);
    }

    // Polishing mixed-language leftovers from Indonesian affixes and grammar.
    $replacements = [
        // Jangan pakai regex awalan Indonesia yang agresif, karena bisa merusak kata English seperti measure -> asure.
        '/\bNo need to measure and mix,?\s*delicious meals are ready faster\b/iu'=>'No need to measure and mix; delicious meals are ready faster',
        '/\bNo need to measure and mix\b/iu'=>'No need to measure and mix',
        '/\band\s+and\b/iu'=>'and','/\bto\s+to\b/iu'=>'to','/\bin\s+in\b/iu'=>'in','/\bwith\s+with\b/iu'=>'with',
        '/\bsiap\b/iu'=>'ready','/\blebih cepat\b/iu'=>'faster','/\bmakanan lezat\b/iu'=>'delicious meals',
        '/\s+([,.!?;:])/u'=>'$1','/[ \t]{2,}/u'=>' ',
    ];
    foreach($replacements as $pat=>$rep){ $html = preg_replace($pat,$rep,$html); }
    $html = preg_replace_callback('/(^|[.!?]\s+)([a-z])/u', function($m){ return $m[1].strtoupper($m[2]); }, $html);
    foreach($tokens as $k=>$v){ $html=str_replace($k,$v,$html); }
    return trim($html);
}
function hydrate_translations($obj){
    if(!$obj || !is_object($obj)) return $obj;
    $vars = get_object_vars($obj);
    $isEnglishPage = (($GLOBALS['locale'] ?? 'id') === 'en');
    foreach($vars as $field=>$value){
        if(str_ends_with($field, '_en')){
            $base = substr($field, 0, -3);
            $idField = $base.'_id';
            $current = isset($obj->$field) ? trim((string)$obj->$field) : '';
            $source  = isset($obj->$idField) ? trim((string)$obj->$idField) : '';
            if($current === '' && $source !== ''){
                $obj->$field = pazar_translate_to_en($source, true);
            } elseif($isEnglishPage && $current !== '' && pazar_looks_indonesian($current)){
                $obj->$field = pazar_translate_to_en($current, true);
            }
        }
    }
    return $obj;
}
function localized_value($obj,$base){
    $loc = $GLOBALS['locale'] ?? 'id';
    $a = $base.'_'.$loc; $b = $base.'_id'; $c = $base.'_en';
    if($loc === 'en'){
        $value = isset($obj->$a) && trim((string)$obj->$a) !== '' ? $obj->$a : ($obj->$b ?? ($obj->$c ?? ''));
        $fromId = (!isset($obj->$a) || trim((string)$obj->$a)==='');
        return $fromId ? pazar_translate_to_en($value, true) : (pazar_looks_indonesian($value) ? pazar_translate_to_en($value, true) : $value);
    }
    return $obj->$a ?? $obj->$b ?? $obj->$c ?? '';
}

if (!function_exists('pazar_config')) { function pazar_config($key){
    if($key==='app.available_locales') return ['id'=>['name'=>'Indonesian','native'=>'Indonesia','flag'=>'img/Web/Indonesia.svg'], 'en'=>['name'=>'English','native'=>'English (US)','flag'=>'img/Web/USA.svg']];
    if($key==='app.storage_url') return base_url('storage');
    return null;
} }
function envv($key,$default=null){ static $env=null; if($env===null){ $env=[]; $file=ROOTPATH.'.env'; if(is_file($file)){ foreach(file($file) as $line){ $line=trim($line); if($line===''||$line[0]==='#') continue; if(strpos($line,'=')!==false){ [$k,$v]=array_map('trim',explode('=',$line,2)); $env[$k]=trim($v,"'\""); } } } } return $env[$key] ?? $default; }
function __($key){ $loc=$GLOBALS['locale'] ?? 'id'; static $lang=[]; if(!isset($lang[$loc])){ $lang[$loc]=[]; foreach(glob(APPPATH."Language/$loc/*.php") as $f){ $lang[$loc][basename($f,'.php')]=include $f; } } [$file,$item]=array_pad(explode('.',$key,2),2,null); return $lang[$loc][$file][$item] ?? $key; }
function slugify($text){ $text=preg_replace('~[^\pL\d]+~u','-',strtolower($text)); $text=trim($text,'-'); return $text ?: 'item'; }
function route($name,$params=[]){
    $loc=$GLOBALS['locale'] ?? 'id'; if(is_string($params)) $params=[$params];
    $map=[
        'language.switch'=>function($p){return 'language/'.($p[0]??'id');}, 'theme.toggle'=>fn()=> 'theme/toggle',
        'id.index'=>fn()=> 'id', 'en.index'=>fn()=> 'en',
        'id.company'=>fn()=> 'id/perusahaan-kami', 'en.company'=>fn()=> 'en/our-company',
        'id.brand'=>fn()=> 'id/brand-kami', 'en.brand'=>fn()=> 'en/our-brand',
        'id.products'=>fn()=> 'id/produk', 'en.products'=>fn()=> 'en/products',
        'id.products.download-catalog'=>fn()=> 'id/produk/unduh-katalog', 'en.products.download-catalog'=>fn()=> 'en/products/download-catalog',
        'id.product.show'=>fn($p)=> 'id/produk/'.($p[0]??''), 'en.product.show'=>fn($p)=> 'en/product/'.($p[0]??''),
        'id.recipes'=>fn()=> 'id/resep', 'en.recipes'=>fn()=> 'en/recipes',
        'id.blogs'=>fn()=> 'id/blog', 'en.blogs'=>fn()=> 'en/blog',
        'id.blog.show'=>fn($p)=> 'id/blog/'.($p[0]??''), 'en.blog.show'=>fn($p)=> 'en/blog/'.($p[0]??''),
        'id.recipe.show'=>fn($p)=> 'id/resep/'.($p[0]??''), 'en.recipe.show'=>fn($p)=> 'en/recipe/'.($p[0]??''),
        'id.careerinfo'=>fn()=> 'id/info-karir', 'en.careerinfo'=>fn()=> 'en/career-info',
        'id.vacancies'=>fn()=> 'id/lowongan', 'en.vacancies'=>fn()=> 'en/vacancies',
        'id.vacancy.show'=>fn($p)=> 'id/lowongan/'.($p[0]??''), 'en.vacancy.show'=>fn($p)=> 'en/vacancy/'.($p[0]??''),
    ];
    $path=isset($map[$name]) ? $map[$name]($params) : str_replace('.','/',$name);
    return base_url($path);
}

function db(){ static $pdo=null; if($pdo) return $pdo; $host=envv('database.default.hostname','localhost'); $db=envv('database.default.database',''); $user=envv('database.default.username','root'); $pass=envv('database.default.password',''); try{ $pdo=new PDO("mysql:host=$host;dbname=$db;charset=utf8mb4",$user,$pass,[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_OBJ]); }catch(Exception $e){ $pdo=false; } return $pdo; }
function rows($sql,$params=[]){ $pdo=db(); if(!$pdo) return []; try{ $st=$pdo->prepare($sql); $st->execute($params); $all=$st->fetchAll(); foreach($all as $o){ hydrate_translations($o); } return $all; }catch(Exception $e){ return []; } }
function row($sql,$params=[]){ $r=rows($sql,$params); return $r[0]??null; }
function storage_url($path){ if(!$path) return null; if(preg_match('~^https?://~',$path)) return $path; return base_url('storage/'.ltrim($path,'/')); }
function hydrate_images($obj){ if(!$obj) return $obj; hydrate_translations($obj); foreach($obj as $k=>$v){ if(is_string($v) && preg_match('~_(image|icon)$|^.*image$|^.*icon$~',$k) && $v) $obj->$k=storage_url($v); } return $obj; }

function pazar_file_url($path, $table='', $field=''){
    $path = trim((string)$path);
    if($path==='') return '';
    if(preg_match('~^https?://~i',$path)) return $path;
    $try=[];
    $try[] = 'storage/'.ltrim($path,'/');
    if(!str_contains($path,'/')){
        $folder = function_exists('admin_upload_folder') ? admin_upload_folder($table,$field) : 'uploads';
        $try[] = 'storage/'.$folder.'/'.$path;
        $try[] = 'storage/products/'.$path;
        $try[] = 'storage/recipes/'.$path;
        $try[] = 'storage/headers/'.$path;
        $try[] = 'storage/certifications/'.$path;
        $try[] = 'img/Product/'.$path;
        $try[] = 'img/Recipe/'.$path;
        $try[] = 'img/Web/'.$path;
    }
    foreach($try as $rel){ if(is_file(PUBLICPATH.$rel)) return base_url($rel); }
    return base_url($try[0]);
}
function pazar_is_image_path($path){ return preg_match('~\.(jpe?g|png|webp|gif|svg)$~i',(string)$path); }
function admin_optimize_image_file($file,$ext,$max=1600,$quality=82){
    $ext=strtolower((string)$ext);
    if(!is_file($file) || !in_array($ext,['jpg','jpeg','png','webp'],true) || !function_exists('getimagesize') || !function_exists('imagecreatetruecolor')) return false;
    $info=@getimagesize($file); if(!$info) return false;
    [$w,$h]=$info; if($w<1 || $h<1) return false;
    $src=null;
    if(($ext==='jpg'||$ext==='jpeg') && function_exists('imagecreatefromjpeg')) $src=@imagecreatefromjpeg($file);
    elseif($ext==='png' && function_exists('imagecreatefrompng')) $src=@imagecreatefrompng($file);
    elseif($ext==='webp' && function_exists('imagecreatefromwebp')) $src=@imagecreatefromwebp($file);
    if(!$src) return false;
    $ratio=min(1, $max/$w, $max/$h); $nw=max(1,(int)round($w*$ratio)); $nh=max(1,(int)round($h*$ratio));
    $dst=imagecreatetruecolor($nw,$nh);
    if(in_array($ext,['png','webp'],true)){ imagealphablending($dst,false); imagesavealpha($dst,true); $transparent=imagecolorallocatealpha($dst,0,0,0,127); imagefilledrectangle($dst,0,0,$nw,$nh,$transparent); }
    imagecopyresampled($dst,$src,0,0,0,0,$nw,$nh,$w,$h);
    $ok=false;
    if($ext==='png' && function_exists('imagepng')) $ok=@imagepng($dst,$file,7);
    elseif($ext==='webp' && function_exists('imagewebp')) $ok=@imagewebp($dst,$file,$quality);
    elseif(function_exists('imagejpeg')) $ok=@imagejpeg($dst,$file,$quality);
    imagedestroy($src); imagedestroy($dst); return $ok;
}

function pazar_bootstrap_v16(){
    static $done=false; if($done) return; $done=true;
    $pdo=db(); if(!$pdo) return;
    $sqls=[];
    $sqls[]="CREATE TABLE IF NOT EXISTS pazar_blog_category (
        bc_id INT AUTO_INCREMENT PRIMARY KEY,
        bc_title_id VARCHAR(190) NOT NULL,
        bc_title_en VARCHAR(190) DEFAULT NULL,
        bc_slug_id VARCHAR(220) DEFAULT NULL,
        bc_slug_en VARCHAR(220) DEFAULT NULL,
        bc_description_id TEXT NULL,
        bc_description_en TEXT NULL,
        bc_is_active TINYINT(1) NOT NULL DEFAULT 1,
        bc_created_at DATETIME NULL,
        bc_updated_at DATETIME NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
    $sqls[]="CREATE TABLE IF NOT EXISTS pazar_blog (
        b_id INT AUTO_INCREMENT PRIMARY KEY,
        b_title_id VARCHAR(220) NOT NULL,
        b_title_en VARCHAR(220) DEFAULT NULL,
        b_slug_id VARCHAR(240) DEFAULT NULL,
        b_slug_en VARCHAR(240) DEFAULT NULL,
        b_excerpt_id TEXT NULL,
        b_excerpt_en TEXT NULL,
        b_content_id LONGTEXT NULL,
        b_content_en LONGTEXT NULL,
        b_image VARCHAR(255) DEFAULT NULL,
        b_category_id INT NULL,
        b_status VARCHAR(30) NOT NULL DEFAULT 'published',
        b_is_featured TINYINT(1) NOT NULL DEFAULT 0,
        b_publish_at DATETIME NULL,
        b_meta_title_id VARCHAR(220) DEFAULT NULL,
        b_meta_title_en VARCHAR(220) DEFAULT NULL,
        b_meta_description_id TEXT NULL,
        b_meta_description_en TEXT NULL,
        b_focus_keyword_id VARCHAR(190) DEFAULT NULL,
        b_focus_keyword_en VARCHAR(190) DEFAULT NULL,
        b_is_active TINYINT(1) NOT NULL DEFAULT 1,
        b_created_by VARCHAR(120) DEFAULT NULL,
        b_updated_by VARCHAR(120) DEFAULT NULL,
        b_created_at DATETIME NULL,
        b_updated_at DATETIME NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
    $sqls[]="CREATE TABLE IF NOT EXISTS pazar_blog_comment (
        bcmt_id INT AUTO_INCREMENT PRIMARY KEY,
        bcmt_blog_id INT NOT NULL,
        bcmt_name VARCHAR(160) NOT NULL,
        bcmt_email VARCHAR(190) DEFAULT NULL,
        bcmt_message TEXT NOT NULL,
        bcmt_status VARCHAR(30) NOT NULL DEFAULT 'pending',
        bcmt_created_at DATETIME NULL,
        INDEX (bcmt_blog_id),
        INDEX (bcmt_status)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
    $sqls[]="CREATE TABLE IF NOT EXISTS pazar_media_library (
        m_id INT AUTO_INCREMENT PRIMARY KEY,
        m_title VARCHAR(220) DEFAULT NULL,
        m_file VARCHAR(255) NOT NULL,
        m_alt_id VARCHAR(220) DEFAULT NULL,
        m_alt_en VARCHAR(220) DEFAULT NULL,
        m_caption_id TEXT NULL,
        m_caption_en TEXT NULL,
        m_mime VARCHAR(100) DEFAULT NULL,
        m_size INT DEFAULT 0,
        m_width INT DEFAULT 0,
        m_height INT DEFAULT 0,
        m_used_for VARCHAR(120) DEFAULT NULL,
        m_is_active TINYINT(1) NOT NULL DEFAULT 1,
        m_created_at DATETIME NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
    $sqls[]="CREATE TABLE IF NOT EXISTS pazar_frontend_menu (
        fm_id INT AUTO_INCREMENT PRIMARY KEY,
        fm_title_id VARCHAR(160) NOT NULL,
        fm_title_en VARCHAR(160) DEFAULT NULL,
        fm_url_id VARCHAR(255) DEFAULT NULL,
        fm_url_en VARCHAR(255) DEFAULT NULL,
        fm_parent_id INT DEFAULT NULL,
        fm_sort_order INT NOT NULL DEFAULT 0,
        fm_target VARCHAR(20) DEFAULT '_self',
        fm_is_active TINYINT(1) NOT NULL DEFAULT 1,
        fm_created_at DATETIME NULL,
        fm_updated_at DATETIME NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
    $sqls[]="CREATE TABLE IF NOT EXISTS pazar_page_blocks (
        pb_id INT AUTO_INCREMENT PRIMARY KEY,
        pb_page VARCHAR(80) NOT NULL,
        pb_type VARCHAR(60) NOT NULL DEFAULT 'text_image',
        pb_title_id VARCHAR(220) DEFAULT NULL,
        pb_title_en VARCHAR(220) DEFAULT NULL,
        pb_content_id LONGTEXT NULL,
        pb_content_en LONGTEXT NULL,
        pb_image VARCHAR(255) DEFAULT NULL,
        pb_button_text_id VARCHAR(160) DEFAULT NULL,
        pb_button_text_en VARCHAR(160) DEFAULT NULL,
        pb_button_url VARCHAR(255) DEFAULT NULL,
        pb_sort_order INT NOT NULL DEFAULT 0,
        pb_is_active TINYINT(1) NOT NULL DEFAULT 1,
        pb_created_at DATETIME NULL,
        pb_updated_at DATETIME NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
    $sqls[]="CREATE TABLE IF NOT EXISTS pazar_content_revisions (
        cr_id INT AUTO_INCREMENT PRIMARY KEY,
        cr_table VARCHAR(120) NOT NULL,
        cr_record_id VARCHAR(80) NOT NULL,
        cr_action VARCHAR(40) NOT NULL,
        cr_snapshot LONGTEXT NULL,
        cr_user VARCHAR(160) DEFAULT NULL,
        cr_created_at DATETIME NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
    $sqls[]="CREATE TABLE IF NOT EXISTS pazar_seo_global (
        sg_id INT AUTO_INCREMENT PRIMARY KEY,
        sg_key VARCHAR(120) NOT NULL UNIQUE,
        sg_value_id TEXT NULL,
        sg_value_en TEXT NULL,
        sg_is_active TINYINT(1) NOT NULL DEFAULT 1,
        sg_updated_at DATETIME NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
    $sqls[]="CREATE TABLE IF NOT EXISTS pazar_admin_notifications (
        an_id INT AUTO_INCREMENT PRIMARY KEY,
        an_title VARCHAR(220) NOT NULL,
        an_message TEXT NULL,
        an_type VARCHAR(50) DEFAULT 'info',
        an_is_read TINYINT(1) NOT NULL DEFAULT 0,
        an_created_at DATETIME NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
    $sqls[]="CREATE TABLE IF NOT EXISTS login_users (
        u_id INT AUTO_INCREMENT PRIMARY KEY,
        u_uuid VARCHAR(80) DEFAULT NULL,
        u_code VARCHAR(80) DEFAULT NULL,
        u_name VARCHAR(160) NOT NULL,
        u_email VARCHAR(190) NOT NULL UNIQUE,
        u_password VARCHAR(255) NOT NULL,
        u_profile_image VARCHAR(255) DEFAULT NULL,
        u_role VARCHAR(80) DEFAULT 'admin',
        u_is_active TINYINT(1) NOT NULL DEFAULT 1,
        u_created_at DATETIME NULL,
        u_updated_at DATETIME NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
    foreach($sqls as $q){ try{$pdo->exec($q);}catch(Exception $e){} }
    try{
        $cols=$pdo->query("SHOW COLUMNS FROM login_users")->fetchAll(PDO::FETCH_COLUMN);
        if(is_array($cols)){
            if(!in_array('u_profile_image',$cols,true)){ $pdo->exec("ALTER TABLE login_users ADD COLUMN u_profile_image VARCHAR(255) DEFAULT NULL AFTER u_password"); $cols[]='u_profile_image'; }
            if(!in_array('u_role',$cols,true)){ $after=in_array('u_profile_image',$cols,true)?'u_profile_image':'u_password'; $pdo->exec("ALTER TABLE login_users ADD COLUMN u_role VARCHAR(80) DEFAULT 'admin' AFTER `$after`"); $cols[]='u_role'; }
            if(!in_array('u_is_active',$cols,true)){ $pdo->exec("ALTER TABLE login_users ADD COLUMN u_is_active TINYINT(1) NOT NULL DEFAULT 1 AFTER u_role"); $cols[]='u_is_active'; }
            if(!in_array('u_updated_at',$cols,true)){ $pdo->exec("ALTER TABLE login_users ADD COLUMN u_updated_at DATETIME NULL"); }
        }
    }catch(Exception $e){}
    try{
        $c=$pdo->query("SELECT COUNT(*) FROM pazar_blog_category")->fetchColumn();
        if((int)$c===0){ rows("INSERT INTO pazar_blog_category (bc_title_id,bc_title_en,bc_slug_id,bc_slug_en,bc_description_id,bc_description_en,bc_is_active,bc_created_at) VALUES ('Tips Masak','Cooking Tips','tips-masak','cooking-tips','Tips dan inspirasi memasak bersama Pazar Seasonings.','Cooking tips and inspiration with Pazar Seasonings.',1,NOW())"); }
        $b=$pdo->query("SELECT COUNT(*) FROM pazar_blog")->fetchColumn();
        if((int)$b===0){ rows("INSERT INTO pazar_blog (b_title_id,b_title_en,b_slug_id,b_slug_en,b_excerpt_id,b_excerpt_en,b_content_id,b_content_en,b_category_id,b_status,b_is_active,b_created_at) VALUES ('Cara Membuat Masakan Lebih Praktis dengan Bumbu Siap Pakai','How to Make Cooking Easier with Ready-to-Use Seasonings','cara-membuat-masakan-lebih-praktis','make-cooking-easier-with-ready-to-use-seasonings','Inspirasi sederhana agar proses memasak lebih cepat, konsisten, dan tetap lezat.','Simple inspiration to make cooking faster, more consistent, and still delicious.','<p>Bumbu siap pakai membantu proses memasak menjadi lebih cepat tanpa mengurangi cita rasa. Dengan takaran yang konsisten, hasil masakan lebih mudah dijaga.</p>','<p>Ready-to-use seasonings help make cooking faster without compromising flavor. With consistent measurements, your dishes are easier to perfect.</p>',1,'published',1,NOW())"); }
        try{
            $hc=$pdo->query("SELECT COUNT(*) FROM pazar_history WHERE hs_year='2024'")->fetchColumn();
            if((int)$hc===0){ rows("INSERT INTO pazar_history (hs_year,hs_description_id,hs_description_en,hs_image) VALUES (?,?,?,?)", ['2024','PT. Pristine Prima Lestari terus melangkah maju sebagai produsen pangan nasional yang terpercaya, inovatif, dan siap bersaing di pasar global.','PT. Pristine Prima Lestari continues to move forward as a trusted, innovative national food producer, ready to compete in the global market.','histories/1748230570_2022.webp']); }
        }catch(Exception $e){}
        try{
            $uc=$pdo->query("SELECT COUNT(*) FROM login_users WHERE u_email='admin@pazarseasonings.com'")->fetchColumn();
            if((int)$uc===0){ $cols=$pdo->query("SHOW COLUMNS FROM login_users")->fetchAll(PDO::FETCH_COLUMN); $data=['u_name'=>'Administrator','u_email'=>'admin@pazarseasonings.com','u_password'=>password_hash('admin123', PASSWORD_DEFAULT),'u_role'=>'super_admin','u_is_active'=>1]; if(in_array('u_employee_id',$cols,true)) $data['u_employee_id']='ADM001'; if(in_array('u_join_date',$cols,true)) $data['u_join_date']=date('Y-m-d'); if(in_array('u_created_by',$cols,true)) $data['u_created_by']='SYSTEM'; if(in_array('u_created_at',$cols,true)) $data['u_created_at']=date('Y-m-d H:i:s'); $keys=array_keys($data); rows("INSERT INTO login_users (`".implode('`,`',$keys)."`) VALUES (".implode(',',array_fill(0,count($keys),'?')).")", array_values($data)); }
        }catch(Exception $e){}
    }catch(Exception $e){}
}
function footerData(){ $items=rows("SELECT * FROM pazar_footer ORDER BY f_id"); foreach($items as $i) hydrate_images($i); return ['address'=>array_values(array_filter($items,fn($x)=>$x->f_type==='alamat'))[0]??null,'contacts'=>array_values(array_filter($items,fn($x)=>$x->f_type==='kontak')),'socials'=>array_values(array_filter($items,fn($x)=>$x->f_type==='social'))]; }

function extract_inline_sections(&$src){
    $sections=[]; $needle="@section('"; $pos=0;
    while(($i=strpos($src,$needle,$pos))!==false){
        $nameStart=$i+strlen($needle); $nameEnd=strpos($src,"'",$nameStart); if($nameEnd===false) break; $name=substr($src,$nameStart,$nameEnd-$nameStart);
        $after=$nameEnd+1; while(isset($src[$after]) && ctype_space($src[$after])) $after++;
        if(($src[$after]??'')!==','){ $pos=$after; continue; }
        $exprStart=$after+1; while(isset($src[$exprStart]) && ctype_space($src[$exprStart])) $exprStart++;
        $j=$exprStart; $depth=0; $q=null; $expr='';
        for(;$j<strlen($src);$j++){ $ch=$src[$j];
            if($q){ if($ch===$q && ($j==0 || $src[$j-1] !== '\\')) $q=null; $expr.=$ch; continue; }
            if($ch==='"' || $ch==="'"){ $q=$ch; $expr.=$ch; continue; }
            if($ch==='(' || $ch==='['){ $depth++; $expr.=$ch; continue; }
            if($ch===')' || $ch===']'){ if($depth===0){ break; } $depth--; $expr.=$ch; continue; }
            $expr.=$ch;
        }
        try{ $sections[$name]=eval('return '.$expr.';'); }catch(Throwable $e){ $sections[$name]=''; }
        $src=substr($src,0,$i).substr($src,$j+1); $pos=$i;
    }
    return $sections;
}
function render($view,$data=[]){ extract($data); $theme=$_COOKIE['theme']??'light'; $footerData=$footerData??footerData(); $file=VIEWPATH.$view.'.blade.php'; if(!is_file($file)) return "View $view not found"; $src=file_get_contents($file); $sections=extract_inline_sections($src);
    if(preg_match_all("/@section\('([^']+)'\)(.*?)@endsection/s",$src,$m,PREG_SET_ORDER)){ foreach($m as $mm){ $sections[$mm[1]]=compile($mm[2]); } }
    if(preg_match("/@extends\('([^']+)'\)/",$src,$ex)){ $master=file_get_contents(VIEWPATH.$ex[1].'.blade.php'); $master=preg_replace_callback("/@yield\('([^']+)'(?:\s*,\s*([^\)]*))?\)/",function($y)use($sections){ return $sections[$y[1]] ?? (isset($y[2])?trim($y[2],"'\""):''); },$master); $php=compile($master); } else { $php=compile($src); }
    ob_start(); eval('?>'.$php); return pazar_optimize_frontend_html(ob_get_clean()); }

function blade_expr_directive($s,$name,$open,$close){
    $needle='@'.$name.'('; $out=''; $pos=0; $len=strlen($s);
    while(($i=strpos($s,$needle,$pos))!==false){
        $out.=substr($s,$pos,$i-$pos); $j=$i+strlen($needle); $depth=1; $q=null; $expr='';
        for(;$j<$len;$j++){ $ch=$s[$j];
            if($q){ if($ch===$q && ($j==0 || $s[$j-1] !== '\\')) $q=null; $expr.=$ch; continue; }
            if($ch==='"' || $ch==="'"){ $q=$ch; $expr.=$ch; continue; }
            if($ch==='('){ $depth++; $expr.=$ch; continue; }
            if($ch===')'){ $depth--; if($depth===0){ $j++; break; } $expr.=$ch; continue; }
            $expr.=$ch;
        }
        $out.=$open.$expr.$close; $pos=$j;
    }
    return $out.substr($s,$pos);
}
function compile($s){
    $s=preg_replace('/{{--.*?--}}/s','',$s);
    $s=preg_replace('/@csrf/','<input type="hidden" name="csrf" value="">',$s);
    $s=preg_replace('/@php\s*(.*?)\s*@endphp/s','<?php $1 ?>',$s);
    $s=preg_replace('/@extends\([^\)]*\)/','',$s);
    $s=preg_replace('/@endsection/','',$s);
    foreach([['if','<?php if(','): ?>'],['elseif','<?php elseif(','): ?>'],['foreach','<?php foreach(','): ?>'],['for','<?php for(','): ?>'],['isset','<?php if(isset(', ')): ?>'],['empty','<?php if(empty(', ')): ?>']] as $d){ $s=blade_expr_directive($s,$d[0],$d[1],$d[2]); }
    $simple=['/@else/'=>'<?php else: ?>','/@endif/'=>'<?php endif; ?>','/@endforeach/'=>'<?php endforeach; ?>','/@endfor/'=>'<?php endfor; ?>','/@endisset/'=>'<?php endif; ?>','/@endempty/'=>'<?php endif; ?>'];
    foreach($simple as $p=>$r) $s=preg_replace($p,$r,$s);
    $s=preg_replace('/{!!\s*(.*?)\s*!!}/s','<?= $1 ?>',$s);
    $s=preg_replace('/{{\s*(.*?)\s*}}/s','<?= e($1) ?>',$s);
    return $s;
}

function pageData($page){ $loc=$GLOBALS['locale']??'id'; $data=['theme'=>$_COOKIE['theme']??'light','footerData'=>footerData()];
    $data['header']=hydrate_images(row("SELECT * FROM pazar_headers WHERE h_page_name=?",[$page]));
    $data['popup']=hydrate_images(row("SELECT * FROM pazar_popup WHERE pu_is_active=1 ORDER BY pu_id DESC LIMIT 1"));
    $data['productCategories']=rows("SELECT * FROM pazar_product_category ORDER BY pc_id"); foreach($data['productCategories'] as $x) hydrate_images($x);
    $data['whyPazarItems']=rows("SELECT * FROM pazar_why_pazar ORDER BY w_id"); foreach($data['whyPazarItems'] as $x) hydrate_images($x);
    $data['latestRecipe']=normalize_recipe(row("SELECT * FROM pazar_recipe WHERE r_is_active=1 ORDER BY r_id DESC LIMIT 1"));
    return $data;
}
function viewPage($view,$page,$extra=[]){ echo render($view,array_merge(pageData($page),$extra)); exit; }


function normalize_product($p){
    if(!$p) return $p;
    hydrate_images($p);
    $p->category_name_id = $p->pc_title_id ?? $p->category_name_id ?? '';
    $p->category_name_en = $p->pc_title_en ?? $p->category_name_en ?? '';
    $p->slug = slugify((($GLOBALS['locale']??'id')==='en') ? ($p->p_title_en ?? $p->p_title_id ?? '') : ($p->p_title_id ?? $p->p_title_en ?? ''));
    $detail = row("SELECT * FROM pazar_product_detail WHERE pd_id_product=?",[$p->p_id ?? 0]);
    if($detail) $p->detail = $detail;
    return $p;
}
function normalize_recipe($r){
    if(!$r) return $r;
    hydrate_images($r);
    $r->slug = slugify((($GLOBALS['locale']??'id')==='en') ? ($r->r_title_en ?? $r->r_title_id ?? '') : ($r->r_title_id ?? $r->r_title_en ?? ''));
    $detail = row("SELECT * FROM pazar_recipe_detail WHERE rd_id_recipe=?",[$r->r_id ?? 0]);
    if($detail) $r->detail = $detail;
    $cats = rows("SELECT c.* FROM pazar_recipe_category c JOIN pazar_recipe_category_junction j ON j.rcj_id_category=c.rc_id WHERE j.rcj_id_recipe=?",[$r->r_id ?? 0]);
    $r->category_names = array_map(fn($c)=>(($GLOBALS['locale']??'id')==='en'?($c->rc_title_en??$c->rc_title_id):($c->rc_title_id??$c->rc_title_en)), $cats);
    $r->category_name = $r->category_names[0] ?? '';
    return $r;
}
function normalize_vacancy($v){
    if(!$v) return $v;
    $v->slug = slugify((($GLOBALS['locale']??'id')==='en') ? ($v->v_title_en ?? $v->v_title_id ?? '') : ($v->v_title_id ?? $v->v_title_en ?? ''));
    $v->department_name_id = $v->da_title_id ?? '';
    $v->department_name_en = $v->da_title_en ?? '';
    $v->experience_name_id = $v->ex_title_id ?? '';
    $v->experience_name_en = $v->ex_title_en ?? '';
    $v->closed_date_formatted = !empty($v->v_closed_date) ? date('d M Y', strtotime($v->v_closed_date)) : '';
    $v->posted_date_formatted = !empty($v->v_posted_date) ? date('d M Y', strtotime($v->v_posted_date)) : '';
    return $v;
}
function special_admin_path(){ return 'panel-pazar-seasonings'; }
function admin_base($extra=''){
    $base = special_admin_path();
    $extra = trim($extra, '/');
    return base_url($base . ($extra ? '/' . $extra : ''));
}
function admin_current_section(){
    $path = request_path_without_base();
    $base = special_admin_path();
    $rest = trim(substr($path, strlen($base)), '/');
    return $rest ?: 'dashboard';
}
function table_count_safe($table, $where='1=1'){
    $r = row("SELECT COUNT(*) AS total FROM `$table` WHERE $where");
    return (int)($r->total ?? 0);
}
function admin_tables_config(){
    return [
        'layout' => [
            'label' => 'Layout', 'icon' => 'layout-dashboard', 'items' => [
                'pazar_headers' => 'Header Halaman',
                'pazar_popup' => 'Popup',
                'pazar_footer' => 'Footer',
            ]
        ],
        'index' => [
            'label' => 'Index', 'icon' => 'panel-top', 'items' => [
                'pazar_certifications' => 'Certifications',
                'pazar_why_pazar' => 'Why Pazar',
                'pazar_testimonial' => 'Testimonial',
            ]
        ],
        'company' => [
            'label' => 'Our Company', 'icon' => 'building-2', 'items' => [
                'pazar_company_profile' => 'Company Profile',
                'pazar_history' => 'History',
            ]
        ],
        'brand' => [
            'label' => 'Our Brand', 'icon' => 'badge-check', 'items' => [
                'pazar_certifications' => 'Certification',
                'pazar_testimonial' => 'Testimonial Brand',
            ]
        ],
        'product' => [
            'label' => 'Product', 'icon' => 'shopping-bag', 'items' => [
                'pazar_product_category' => 'Product Category',
                'pazar_product' => 'Product',
                'pazar_product_detail' => 'Product Detail / Marketplace',
                'pazar_product_catalog' => 'Product Catalog',
            ]
        ],
        'recipe' => [
            'label' => 'Recipe', 'icon' => 'book-open', 'items' => [
                'pazar_recipe_category' => 'Recipe Category',
                'pazar_recipe' => 'Recipe',
                'pazar_recipe_detail' => 'Recipe Detail',
                'pazar_recipe_category_junction' => 'Recipe Category Junction',
            ]
        ],
        'career' => [
            'label' => 'Career', 'icon' => 'book-open', 'items' => [
                'career_careerinfo' => 'Career Info',
                'career_work_at_pazar' => 'Work At Pazar',
                'career_departments' => 'Departments',
                'career_experiences' => 'Experiences',
            ]
        ],
        'vacancies' => [
            'label' => 'Vacancies', 'icon' => 'briefcase-business', 'items' => [
                'career_vacancies' => 'Vacancies',
            ]
        ],
        'blog' => [
            'label' => 'Blog', 'icon' => 'newspaper', 'items' => [
                'pazar_blog_category' => 'Blog Category',
                'pazar_blog' => 'Blog / Artikel',
                'pazar_blog_comment' => 'Komentar Blog',
            ]
        ],
    ];
}
function admin_allowed_tables($user){
    $email = strtolower($user->u_email ?? '');
    $all=[]; foreach(admin_tables_config() as $g){ foreach($g['items'] as $t=>$l) $all[$t]=$l; }
    if($email === 'sosmed@pazarseasonings.com'){
        return array_intersect_key($all, array_flip(['pazar_headers','pazar_popup','pazar_product_category','pazar_product','pazar_product_detail','pazar_product_catalog','pazar_recipe_category','pazar_recipe','pazar_recipe_detail','pazar_recipe_category_junction','pazar_blog_category','pazar_blog','pazar_blog_comment','pazar_media_library']));
    }
    return $all;
}

function admin_is_super_admin($user=null){ $user=$user ?: ($_SESSION['admin'] ?? null); return strtolower($user->u_email ?? '') === 'admin@pazarseasonings.com'; }
function admin_is_sosmed($user=null){ $user=$user ?: ($_SESSION['admin'] ?? null); return strtolower($user->u_email ?? '') === 'sosmed@pazarseasonings.com'; }
function admin_can_delete_table($table){ return admin_is_super_admin(); }
function admin_log_path(){ $dir=ROOTPATH.'writable'.DIRECTORY_SEPARATOR.'logs'; if(!is_dir($dir)) @mkdir($dir,0775,true); return $dir.DIRECTORY_SEPARATOR.'pazar_admin_activity.jsonl'; }
function admin_log_activity($action,$table='',$record='',$note=''){
    $u=$_SESSION['admin'] ?? null;
    $row=['time'=>date('c'),'user'=>$u->u_email ?? 'guest','action'=>$action,'table'=>$table,'record'=>(string)$record,'note'=>$note,'ip'=>$_SERVER['REMOTE_ADDR'] ?? ''];
    @file_put_contents(admin_log_path(), json_encode($row,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES)."\n", FILE_APPEND);
}
function admin_save_revision($table,$pk,$id,$action,$snapshot){
    pazar_bootstrap_v16(); $u=$_SESSION['admin'] ?? null;
    try{ rows("INSERT INTO pazar_content_revisions (cr_table,cr_record_id,cr_action,cr_snapshot,cr_user,cr_created_at) VALUES (?,?,?,?,?,NOW())", [$table,(string)$id,$action,json_encode($snapshot,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),$u->u_email ?? 'system']); }catch(Exception $e){}
}
function admin_recent_activity($limit=10){
    $path=admin_log_path(); if(!is_file($path)) return [];
    $lines=@file($path, FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES) ?: [];
    $lines=array_slice($lines, -$limit); $out=[];
    foreach(array_reverse($lines) as $line){ $j=json_decode($line,true); if(is_array($j)) $out[]=$j; }
    return $out;
}
function admin_table_label($table){ foreach(admin_tables_config() as $g){ if(isset($g['items'][$table])) return $g['items'][$table]; } return ucwords(str_replace('_',' ',$table)); }
function admin_cols_names($cols){ return array_map(fn($c)=>$c->Field,$cols); }
function admin_has_col($cols,$field){ return in_array($field, admin_cols_names($cols), true); }
function admin_active_field($cols){ foreach(admin_cols_names($cols) as $n){ if(preg_match('~(^|_)is_active$~',$n)) return $n; } return null; }
function admin_title_field($cols){ foreach(admin_cols_names($cols) as $n){ if(preg_match('~(_title_id|_name_id|title_id|name_id)$~',$n)) return $n; } foreach(admin_cols_names($cols) as $n){ if(preg_match('~(title|name|judul|nama)~i',$n)) return $n; } return $cols[0]->Field ?? ''; }
function admin_slug_field($cols){ foreach(admin_cols_names($cols) as $n){ if(preg_match('~(^|_)slug(_id|_en)?$~i',$n)) return $n; } return null; }
function admin_translation_status($item,$pairs){
    if(!$pairs) return ['none','Tidak ada kolom English']; $total=0; $ok=0; $bad=0; $empty=0;
    foreach($pairs as $id=>$en){ $src=trim((string)($item->$id ?? '')); if($src==='') continue; $total++; $val=trim((string)($item->$en ?? '')); if($val===''){$empty++; continue;} if(pazar_looks_indonesian($val)){$bad++; continue;} $ok++; }
    if($total===0) return ['none','Tidak ada sumber ID'];
    if($ok===$total) return ['ok','English OK'];
    if($bad>0) return ['warn','Perlu cek manual'];
    if($empty>0) return ['empty','Belum English'];
    return ['warn','Perlu cek'];
}
function admin_seo_status($item,$cols){
    $names=admin_cols_names($cols); $need=[];
    foreach($names as $n){ if(preg_match('~(meta_title|meta_description|focus_keyword|seo_title|seo_description)~i',$n)) $need[]=$n; }
    if(!$need) return ['none','SEO opsional'];
    $filled=0; foreach($need as $n){ if(trim((string)($item->$n ?? ''))!=='') $filled++; }
    if($filled===count($need)) return ['ok','SEO OK'];
    if($filled>0) return ['warn','SEO belum lengkap'];
    return ['empty','SEO kosong'];
}
function admin_badge($status,$text){
    $map=['ok'=>'bg-emerald-900/60 text-emerald-200 border-emerald-700','warn'=>'bg-amber-900/60 text-amber-200 border-amber-700','empty'=>'bg-rose-900/60 text-rose-200 border-rose-700','none'=>'bg-slate-800 text-slate-300 border-slate-600'];
    $cls=$map[$status] ?? $map['none']; return '<span class="inline-flex items-center rounded-full border px-2.5 py-1 text-xs '.$cls.'">'.e($text).'</span>';
}
function admin_preview_urls($table,$item,$cols){
    $titleField=admin_title_field($cols); $title=trim((string)($item->$titleField ?? '')); $slug=slugify($title); $urls=[];
    if($table==='pazar_product'){ $urls['ID']=base_url('id/produk/'.$slug); $urls['EN']=base_url('en/product/'.$slug); }
    elseif($table==='pazar_blog'){ $urls['ID']=base_url('id/blog/'.$slug); $urls['EN']=base_url('en/blog/'.$slug); }
    elseif($table==='pazar_recipe'){ $urls['ID']=base_url('id/resep/'.$slug); $urls['EN']=base_url('en/recipe/'.$slug); }
    elseif($table==='career_vacancies'){ $urls['ID']=base_url('id/lowongan/'.$slug); $urls['EN']=base_url('en/vacancy/'.$slug); }
    elseif(in_array($table,['pazar_company_profile','pazar_history'],true)){ $urls['ID']=base_url('id/perusahaan-kami'); $urls['EN']=base_url('en/our-company'); }
    elseif(in_array($table,['pazar_certifications','pazar_testimonial'],true)){ $urls['ID']=base_url('id/brand-kami'); $urls['EN']=base_url('en/our-brand'); }
    elseif($table==='pazar_why_pazar'){ $urls['ID']=base_url('id'); $urls['EN']=base_url('en'); }
    return $urls;
}
function admin_dashboard_translation_summary(){
    $allowed=admin_allowed_tables($_SESSION['admin'] ?? null); $summary=['ok'=>0,'warn'=>0,'empty'=>0,'none'=>0,'total'=>0];
    foreach($allowed as $t=>$label){ $cols=rows("SHOW COLUMNS FROM ".admin_ident($t)); if(!$cols) continue; $pairs=admin_translation_pairs($cols); if(!$pairs) continue; $pk=$cols[0]->Field; $items=rows("SELECT * FROM ".admin_ident($t)." ORDER BY ".admin_ident($pk)." DESC LIMIT 500"); foreach($items as $it){ [$st,$txt]=admin_translation_status($it,$pairs); $summary[$st]++; $summary['total']++; } }
    return $summary;
}

function admin_shell_start($title='Dashboard', $activeTable=''){
    pazar_bootstrap_v16();
    $user = $_SESSION['admin'] ?? null;
    $allowed = admin_allowed_tables($user);
    $config = admin_tables_config();
    $email = e($user->u_email ?? '');
    $name = e(($user->u_name ?? '') ?: 'Pazar Admin');
    $profile = e(storage_url($user->u_profile_image ?? '') ?: asset('img/Web/Logo.webp'));
    echo '<!doctype html><html lang="en" class="dark"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>'.e($title).' - Pazar Website Admin</title><link rel="icon" href="'.asset('favicon.ico').'"><link rel="shortcut icon" href="'.asset('favicon.ico').'"><link rel="apple-touch-icon" href="'.asset('favicon.png').'"><script src="https://cdn.tailwindcss.com"></script><script defer src="https://unpkg.com/lucide@latest"></script><script>tailwind.config={darkMode:"class",theme:{extend:{colors:{accent:"#BF161C","gray-custom":"#E0FBFC","bg-dark":"#253237"}}}}</script><style>
        :root{--sidebar-w:256px;--topbar-h:64px;--bg:#253237;--panel:#1f2937;--panel2:#0f172a;--line:#334155;--text:#e0fbfc;--muted:#94a3b8;--accent:#BF161C}
        *{box-sizing:border-box} body{margin:0;background:var(--bg);color:var(--text);font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}.admin-topbar{position:fixed;top:0;left:0;right:0;height:var(--topbar-h);z-index:60;background:var(--bg);border-bottom:1px solid var(--line);display:flex;align-items:center;justify-content:space-between;padding:0 18px}.admin-sidebar{position:fixed;top:var(--topbar-h);left:0;bottom:0;width:var(--sidebar-w);z-index:50;background:var(--bg);border-right:1px solid var(--line);overflow-y:auto;padding:16px;transition:transform .25s ease}.admin-main{padding-top:var(--topbar-h);padding-left:var(--sidebar-w);min-height:100vh;transition:padding-left .25s ease}.admin-content{padding:28px;max-width:1600px}.sidebar-collapsed .admin-sidebar{transform:translateX(calc(-1 * var(--sidebar-w)))}.sidebar-collapsed .admin-main{padding-left:0}.admin-link{display:flex;align-items:center;gap:12px;padding:10px 12px;border-radius:10px;text-decoration:none;color:var(--text);margin-bottom:6px}.admin-link:hover,.admin-link.active{background:linear-gradient(135deg,#164e2c,#10b981);color:#fff;box-shadow:0 10px 22px rgba(16,185,129,.18)}.admin-group-title{width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 12px;border:0;background:transparent;color:var(--text);border-radius:10px;cursor:pointer;font:inherit}.admin-group-title:hover{background:#334155}.admin-submenu{margin-left:20px;padding-left:12px;border-left:1px solid #475569;margin-bottom:6px}.admin-submenu a{display:block;color:#cbd5e1;text-decoration:none;font-size:14px;padding:9px 12px;border-radius:8px}.admin-submenu a:hover,.admin-submenu a.active{background:#123524;color:#86efac;border-left:3px solid #22c55e}.admin-card{background:#1e293b;border:1px solid var(--line);border-radius:16px;box-shadow:0 14px 28px rgba(0,0,0,.14)}.admin-form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:18px}.blog-editor-layout{display:grid;grid-template-columns:minmax(0,1fr) 360px;gap:20px}.blog-editor-main,.blog-editor-side{display:flex;flex-direction:column;gap:18px}.blog-writer-hero{background:linear-gradient(135deg,#991b1b,#dc2626 55%,#16a34a);border:1px solid rgba(255,255,255,.16);border-radius:22px;padding:22px;box-shadow:0 18px 45px rgba(220,38,38,.20)}.blog-writer-hero h3{font-size:22px;font-weight:900;margin:0 0 8px}.blog-writer-hero p{color:#fee2e2;line-height:1.6;margin:0}.blog-editor-side .admin-card{position:relative;top:auto}.blog-editor-side{align-self:start}.blog-panel-title{display:flex;align-items:center;gap:10px;font-size:16px;font-weight:900;margin:0 0 14px}.seo-preview{background:#f8fafc;color:#111827;border-radius:14px;padding:14px;border:1px solid #e2e8f0}.seo-preview .seo-title{color:#1a0dab;font-size:18px;line-height:1.25;margin-bottom:3px}.seo-preview .seo-url{color:#006621;font-size:13px;margin-bottom:6px}.seo-preview .seo-desc{color:#4b5563;font-size:13px;line-height:1.45}.char-counter{display:flex;justify-content:space-between;gap:10px;font-size:12px;color:#94a3b8;margin-top:6px}.char-counter.good{color:#86efac}.char-counter.warn{color:#fde68a}.char-counter.bad{color:#fca5a5}.blog-checklist{display:grid;gap:9px}.blog-checklist div{display:flex;align-items:center;gap:9px;font-size:13px;color:#cbd5e1}.blog-checklist span{width:20px;height:20px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;background:#334155;color:#94a3b8;font-size:11px}.blog-checklist div.ok span{background:#14532d;color:#86efac}.blog-quick-actions{display:flex;flex-wrap:wrap;gap:8px}.blog-quick-actions button{background:#0f172a;border:1px solid #334155;color:#e2e8f0;border-radius:10px;padding:8px 10px;font-size:12px;font-weight:800}.blog-quick-actions button:hover{border-color:#22c55e;color:#86efac}.admin-field.full{grid-column:1/-1}.admin-label{display:block;font-size:13px;font-weight:700;color:#cbd5e1;margin-bottom:7px}.admin-input,.admin-select,.admin-textarea{width:100%;background:#0f172a;border:1px solid #475569;color:#fff;border-radius:10px;padding:12px 14px;outline:0}.admin-input:focus,.admin-select:focus,.admin-textarea:focus{border-color:#ef4444;box-shadow:0 0 0 3px rgba(191,22,28,.2)}.admin-textarea{min-height:140px;resize:vertical}.admin-help{font-size:12px;color:var(--muted);margin-top:6px}.admin-actions-sticky{position:sticky;bottom:0;background:linear-gradient(180deg,rgba(30,41,59,.75),#1e293b);padding-top:16px;margin-top:8px}.admin-table-wrap{overflow:auto}.admin-table{width:100%;border-collapse:collapse;font-size:14px}.admin-table th{position:sticky;top:0;background:#0f172a;color:#cbd5e1;text-align:left;padding:12px;white-space:nowrap}.admin-table td{border-top:1px solid #334155;padding:12px;vertical-align:top}.admin-scroll::-webkit-scrollbar{width:8px;height:8px}.admin-scroll::-webkit-scrollbar-thumb{background:#64748b;border-radius:999px}.img-preview{height:50px;width:80px;object-fit:cover;border-radius:10px;border:1px solid #475569;background:#111827}.admin-thumb{width:72px;height:52px;object-fit:cover;border-radius:10px;border:1px solid #475569;background:#0f172a}.admin-thumb-link{display:inline-block}.media-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:16px}.media-card{background:linear-gradient(180deg,#1e293b,#111827);border:1px solid #334155;border-radius:18px;overflow:hidden;box-shadow:0 16px 32px rgba(0,0,0,.18)}.media-card-preview{height:160px;background:#0f172a;display:flex;align-items:center;justify-content:center;overflow:hidden}.media-card-preview img{width:100%;height:100%;object-fit:cover}.media-card-body{padding:14px}.copy-input{width:100%;background:#020617;border:1px solid #334155;border-radius:10px;color:#cbd5e1;font-size:12px;padding:9px 10px}.media-upload-box{border:1px dashed #475569;background:#0f172a;border-radius:18px;padding:18px}.media-stat{background:#0f172a;border:1px solid #334155;border-radius:14px;padding:12px}.media-picker-backdrop{display:none;position:fixed;inset:0;z-index:120;background:rgba(2,6,23,.72);backdrop-filter:blur(4px);padding:26px}.media-picker-backdrop.show{display:flex;align-items:center;justify-content:center}.media-picker-box{width:min(1100px,96vw);max-height:88vh;overflow:hidden;background:#1e293b;border:1px solid #475569;border-radius:22px;box-shadow:0 30px 80px rgba(0,0,0,.45);display:flex;flex-direction:column}.media-picker-head{padding:18px 20px;border-bottom:1px solid #334155;display:flex;align-items:center;justify-content:space-between;gap:12px}.media-picker-body{padding:16px 20px;overflow:auto}.media-picker-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:14px}.media-picker-item{background:#0f172a;border:1px solid #334155;border-radius:16px;overflow:hidden}.media-picker-item img{width:100%;height:122px;object-fit:cover;background:#020617}.media-picker-info{padding:11px}.media-picker-title{font-weight:900;font-size:13px;line-height:1.25;min-height:34px}.media-picker-actions{display:grid;grid-template-columns:1fr 1fr;gap:7px;margin-top:10px}.media-picker-actions button{border:0;border-radius:10px;padding:8px 9px;font-size:12px;font-weight:900;cursor:pointer}.media-picker-insert{background:#16a34a;color:#fff}.media-picker-copy{background:#334155;color:#e2e8f0}.media-picker-empty{padding:28px;text-align:center;color:#cbd5e1;background:#0f172a;border:1px dashed #475569;border-radius:16px}.profile-menu{display:none;position:absolute;right:0;top:52px;width:288px;background:#1e293b;border:1px solid #334155;border-radius:14px;box-shadow:0 20px 45px rgba(0,0,0,.35);overflow:hidden}.profile-menu.show{display:block}.profile-menu a{display:block;color:var(--text);text-decoration:none;padding:11px 16px}.profile-menu a:hover{background:#334155}.btn{display:inline-flex;align-items:center;gap:8px;border:0;border-radius:14px;padding:11px 16px;font-weight:800;text-decoration:none;cursor:pointer;transition:.18s ease;box-shadow:0 10px 22px rgba(0,0,0,.14)}.btn:hover{transform:translateY(-1px)}.btn-primary{background:linear-gradient(135deg,#BF161C,#ef4444);color:#fff}.btn-primary:hover{background:linear-gradient(135deg,#8f1015,#dc2626)}.btn-muted{background:linear-gradient(135deg,#334155,#475569);color:#e2e8f0;border:1px solid #64748b}.btn-muted:hover{background:linear-gradient(135deg,#475569,#64748b)}.btn-success{background:linear-gradient(135deg,#15803d,#22c55e);color:#fff}.btn-success:hover{background:linear-gradient(135deg,#166534,#16a34a)}.btn-danger{color:#f87171}.badge{display:inline-flex;padding:4px 9px;border-radius:999px;background:#334155;color:#e2e8f0;font-size:12px}.admin-field.hidden-audit{display:none} details summary::-webkit-details-marker{display:none} input[type=checkbox]{accent-color:#10b981}.mini-toolbar{display:flex;flex-wrap:wrap;gap:6px;margin:0}.mini-toolbar button{background:#334155;color:#e2e8f0;border:1px solid #475569;border-radius:8px;padding:7px 10px;font-size:12px;font-weight:800}.mini-toolbar button:hover,.mini-toolbar button.active{background:#475569}.wp-editor{background:#0f172a;border:1px solid #475569;border-radius:14px;overflow:hidden}.wp-editor-head{display:flex;align-items:center;justify-content:space-between;gap:12px;background:#111827;border-bottom:1px solid #334155;padding:9px 10px}.wp-editor-tabs{display:flex;gap:6px}.wp-editor-tab{background:#1e293b;color:#cbd5e1;border:1px solid #475569;border-radius:8px;padding:6px 11px;font-size:12px;font-weight:800;cursor:pointer}.wp-editor-tab.active{background:#e2e8f0;color:#111827;border-color:#e2e8f0}.wp-editor-body{background:#fff;color:#111827;min-height:310px;padding:0}.wp-editor-visual{min-height:310px;padding:18px 20px;outline:0;line-height:1.7;font-size:16px;font-family:Arial,Helvetica,sans-serif}.wp-editor-visual:focus{box-shadow:inset 0 0 0 3px rgba(191,22,28,.16)}.wp-editor-visual p{margin:0 0 14px}.wp-editor-visual h1{font-size:32px;line-height:1.2;margin:26px 0 14px;font-weight:900}.wp-editor-visual h2{font-size:26px;line-height:1.25;margin:24px 0 12px;font-weight:800}.wp-editor-visual h3{font-size:21px;line-height:1.3;margin:20px 0 10px;font-weight:800}.wp-editor-visual ul,.wp-editor-visual ol{padding-left:26px;margin:0 0 14px}.wp-editor-visual blockquote{border-left:4px solid #BF161C;background:#fff5f5;margin:18px 0;padding:14px 18px;border-radius:10px}.wp-editor-visual hr{border:0;border-top:2px dashed #e5e7eb;margin:24px 0}.wp-editor-visual a{color:#0f65d8;text-decoration:underline}.wp-editor-visual img{max-width:100%;height:auto;border-radius:12px}.wp-editor-visual iframe{width:100%;height:100%;border:0;border-radius:12px}.wp-editor-visual .pazar-media{margin:18px 0}.wp-editor-visual .pazar-media img{width:100%;height:auto}.wp-editor-visual .pazar-media.pazar-width-25{width:25%;max-width:100%}.wp-editor-visual .pazar-media.pazar-width-50{width:50%;max-width:100%}.wp-editor-visual .pazar-media.pazar-width-75{width:75%;max-width:100%}.wp-editor-visual .pazar-media.pazar-width-full{width:100%}.wp-editor-visual .pazar-align-left{margin-right:auto;text-align:left}.wp-editor-visual .pazar-align-center{margin-left:auto;margin-right:auto;text-align:center}.wp-editor-visual .pazar-align-right{margin-left:auto;text-align:right}.wp-editor-visual .pazar-video{aspect-ratio:16/9;overflow:hidden;background:#020617;border-radius:12px}.wp-editor-visual .pazar-video iframe{display:block;width:100%;height:100%}.wp-editor-source{display:none!important;width:100%;min-height:310px;border:0;border-radius:0;background:#020617;color:#f8fafc;font-family:Consolas,Monaco,monospace;font-size:14px;line-height:1.55}.wp-editor.source-mode .wp-editor-visual{display:none}.wp-editor.source-mode .wp-editor-source{display:block!important}.wp-editor.source-mode .wp-editor-body{background:#020617}.wp-editor-toolbar-note{font-size:11px;color:#94a3b8;white-space:nowrap}.wp-editor-empty:before{content:attr(data-placeholder);color:#94a3b8}.upload-preview-box{display:flex;gap:12px;align-items:center;margin-top:10px}.upload-preview-box img{height:86px;width:130px;object-fit:cover;border-radius:12px;border:1px solid #475569;background:#111827}.quick-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px}.quick-card{background:#0f172a;border:1px solid #334155;border-radius:14px;padding:14px;text-decoration:none;color:#e0fbfc}.quick-card:hover{border-color:#ef4444;background:#111c33}.activity-item{border-bottom:1px solid #334155;padding:10px 0}.activity-item:last-child{border-bottom:0}[data-lucide]{display:inline-flex;align-items:center;justify-content:center;min-width:1.15em;min-height:1.15em;color:currentColor}[data-lucide]:empty:before{font-size:1.05em;line-height:1}.lucide-fallback[data-lucide="home"]:before,[data-lucide="home"]:empty:before{content:"🏠"}.lucide-fallback[data-lucide="menu"]:before,[data-lucide="menu"]:empty:before{content:"☰"}.lucide-fallback[data-lucide="user"]:before,[data-lucide="user"]:empty:before{content:"👤"}.lucide-fallback[data-lucide="users"]:before,[data-lucide="users"]:empty:before{content:"👥"}.lucide-fallback[data-lucide="log-out"]:before,[data-lucide="log-out"]:empty:before{content:"↪"}.lucide-fallback[data-lucide="layout-dashboard"]:before,[data-lucide="layout-dashboard"]:empty:before{content:"▦"}.lucide-fallback[data-lucide="panel-top"]:before,[data-lucide="panel-top"]:empty:before{content:"▤"}.lucide-fallback[data-lucide="building-2"]:before,[data-lucide="building-2"]:empty:before{content:"🏢"}.lucide-fallback[data-lucide="badge-check"]:before,[data-lucide="badge-check"]:empty:before{content:"✅"}.lucide-fallback[data-lucide="shopping-bag"]:before,[data-lucide="shopping-bag"]:empty:before{content:"🛍️"}.lucide-fallback[data-lucide="book-open"]:before,[data-lucide="book-open"]:empty:before{content:"📖"}.lucide-fallback[data-lucide="briefcase-business"]:before,[data-lucide="briefcase-business"]:empty:before{content:"💼"}.lucide-fallback[data-lucide="newspaper"]:before,[data-lucide="newspaper"]:empty:before{content:"📰"}.lucide-fallback[data-lucide="settings-2"]:before,[data-lucide="settings-2"]:empty:before{content:"⚙️"}.lucide-fallback[data-lucide="chevron-down"]:before,[data-lucide="chevron-down"]:empty:before{content:"⌄"}.lucide-fallback[data-lucide="save"]:before,[data-lucide="save"]:empty:before{content:"💾"}.tool-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:16px}.tool-card{background:linear-gradient(180deg,#1e293b,#111827);border:1px solid #334155;border-radius:18px;padding:18px;box-shadow:0 16px 32px rgba(0,0,0,.18)}.tool-card h3{font-size:18px;font-weight:900;margin-bottom:8px}.tool-card p{color:#cbd5e1;font-size:14px;line-height:1.55;margin-bottom:14px}.profile-hero{background:linear-gradient(135deg,#122034,#1e293b 55%,#10291d);border:1px solid #334155;border-radius:22px;padding:24px;box-shadow:0 20px 45px rgba(0,0,0,.22)}.profile-avatar{width:128px;height:128px;border-radius:999px;object-fit:cover;background:#0f172a;border:4px solid #10b981;box-shadow:0 16px 35px rgba(16,185,129,.22)}.profile-section-title{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:900;margin-bottom:16px}.profile-note{border:1px dashed #475569;background:#0f172a;border-radius:14px;padding:13px;color:#cbd5e1;font-size:13px;line-height:1.55}.lucide-fallback[data-lucide="lock"]:before,[data-lucide="lock"]:empty:before{content:"🔒"}.lucide-fallback[data-lucide="mail"]:before,[data-lucide="mail"]:empty:before{content:"✉️"}.lucide-fallback[data-lucide="camera"]:before,[data-lucide="camera"]:empty:before{content:"📷"}.lucide-fallback[data-lucide="image"]:before,[data-lucide="image"]:empty:before{content:"🖼️"}.lucide-fallback[data-lucide="copy"]:before,[data-lucide="copy"]:empty:before{content:"📋"}.lucide-fallback[data-lucide="upload"]:before,[data-lucide="upload"]:empty:before{content:"⬆️"}.lucide-fallback[data-lucide="file"]:before,[data-lucide="file"]:empty:before{content:"📄"}.lucide-fallback[data-lucide="x"]:before,[data-lucide="x"]:empty:before{content:"✕"}@media(max-width:1100px){.blog-editor-layout{grid-template-columns:1fr}.blog-editor-side .admin-card{position:static}}@media(max-width:900px){.admin-sidebar{transform:translateX(calc(-1 * var(--sidebar-w)))}.admin-main{padding-left:0}.mobile-sidebar-open .admin-sidebar{transform:translateX(0)}.admin-content{padding:18px}.admin-form-grid{grid-template-columns:1fr}.admin-topbar h1{font-size:16px}}
    </style></head><body class="dark"><header class="admin-topbar"><button id="sidebarToggle" class="btn btn-muted" type="button"><i data-lucide="menu" class="w-5 h-5"></i></button><h1 class="text-xl font-bold">Pazar Website Admin</h1><div class="relative"><button id="profileToggle" type="button" class="w-11 h-11 rounded-full bg-slate-700 overflow-hidden ring-1 ring-slate-600"><img src="'.$profile.'" class="w-full h-full object-cover" onerror="this.src=\''.asset('img/Web/Logo.webp').'\'"></button><div id="profileMenu" class="profile-menu"><div class="px-4 py-3 border-b border-slate-700"><div class="font-semibold text-gray-custom">'.$name.'</div><div class="text-xs text-slate-400">'.$email.'</div></div><a href="'.admin_base('profile').'"><i data-lucide="user" class="inline w-4 h-4 mr-2"></i> My Profile</a><a href="'.admin_base('logout').'"><i data-lucide="log-out" class="inline w-4 h-4 mr-2"></i> Log Out</a></div></div></header><aside class="admin-sidebar admin-scroll"><nav><a class="admin-link '.($title==='Dashboard'?'active':'').'" href="'.admin_base('dashboard').'"><i data-lucide="home" class="w-5 h-5"></i>Dashboard</a>';
    echo '<a class="admin-link '.($title==='Media Library'?'active':'').'" href="'.admin_base('media-library').'"><i data-lucide="image" class="w-5 h-5"></i>Media Library</a>';
    foreach($config as $key=>$group){
        $visibleItems = array_intersect_key($group['items'], $allowed);
        if(!$visibleItems) continue;
        $isOpen = array_key_exists($activeTable, $visibleItems) ? 'display:block' : 'display:none';
        echo '<div class="admin-group"><button type="button" class="admin-group-title" data-group-toggle><span class="flex items-center gap-3"><i data-lucide="'.e($group['icon']).'" class="w-5 h-5"></i>'.e($group['label']).'</span><i data-lucide="chevron-down" class="w-4 h-4"></i></button><div class="admin-submenu" style="'.$isOpen.'">';
        foreach($visibleItems as $t=>$label){ echo '<a class="'.($activeTable===$t?'active':'').'" href="'.admin_base('manage?table='.$t).'">'.e($label).'</a>'; }
        echo '</div></div>';
    }
    if(admin_is_super_admin($user)){ echo '<a class="admin-link '.($title==='Manage User'?'active':'').'" href="'.admin_base('users').'"><i data-lucide="users" class="w-5 h-5"></i>Manage User</a>'; }
    echo '<a class="admin-link '.($title==='My Profile'?'active':'').'" href="'.admin_base('profile').'"><i data-lucide="user" class="w-5 h-5"></i>My Profile</a>';
    echo '</nav></aside><main class="admin-main"><div class="admin-content"><div class="mb-6"><h1 class="text-2xl font-bold">'.e($title).'</h1></div>';
}
function admin_shell_end(){
    echo '</div></main><script>
    (function(){
      var body=document.body, toggle=document.getElementById("sidebarToggle"), profile=document.getElementById("profileToggle"), menu=document.getElementById("profileMenu");
      if(toggle){toggle.addEventListener("click",function(){ if(window.innerWidth<=900){body.classList.toggle("mobile-sidebar-open");}else{body.classList.toggle("sidebar-collapsed");} });}
      document.querySelectorAll("[data-group-toggle]").forEach(function(btn){btn.addEventListener("click",function(){var m=btn.parentElement.querySelector(".admin-submenu"); if(m){m.style.display=(m.style.display==="none"||!m.style.display)?"block":"none";}});});
      if(profile && menu){profile.addEventListener("click",function(e){e.stopPropagation();menu.classList.toggle("show");});document.addEventListener("click",function(){menu.classList.remove("show");});}
      document.addEventListener("click",function(e){var cp=e.target.closest("[data-copy-text]"); if(!cp) return; var txt=cp.getAttribute("data-copy-text")||""; if(navigator.clipboard){navigator.clipboard.writeText(txt);} else {var ta=document.createElement("textarea"); ta.value=txt; document.body.appendChild(ta); ta.select(); document.execCommand("copy"); ta.remove();} var old=cp.innerHTML; cp.innerHTML="Tersalin ✓"; setTimeout(function(){cp.innerHTML=old; if(window.lucide){lucide.createIcons();}},1200);});
      function wpTextToHtml(text){text=(text||"").trim(); if(!text) return ""; if(/<[a-z][\s\S]*>/i.test(text)) return text; return text.split(/\n\s*\n/).map(function(p){return "<p>"+p.replace(/\n/g,"<br>")+"</p>";}).join("");}
      function wpCleanHtml(html){return (html||"").replace(/<div><br><\/div>/g,"<p><br></p>").replace(/<div>/g,"<p>").replace(/<\/div>/g,"</p>");}
      function wpYoutubeEmbed(url){url=(url||"").trim(); var id=""; var m=url.match(/[?&]v=([^&]+)/); if(m) id=m[1]; m=url.match(/youtu\.be\/([^?&]+)/); if(!id&&m) id=m[1]; m=url.match(/embed\/([^?&]+)/); if(!id&&m) id=m[1]; return id?"https://www.youtube.com/embed/"+id:url;}
      function wpSyncOne(box, visualToSource){var source=box.querySelector(".wp-editor-source"), visual=box.querySelector(".wp-editor-visual"); if(!source||!visual) return; if(visualToSource){source.value=wpCleanHtml(visual.innerHTML).trim();}else{visual.innerHTML=wpTextToHtml(source.value); visual.classList.toggle("wp-editor-empty", !visual.textContent.trim());}}
      var activeWpEditor=null, activeMediaTargetInput=null;
      function setActiveWpEditor(box){ if(box) activeWpEditor=box; }
      document.querySelectorAll(".wp-editor").forEach(function(box){wpSyncOne(box,false); var visual=box.querySelector(".wp-editor-visual"), source=box.querySelector(".wp-editor-source"); if(visual){visual.addEventListener("focus",function(){setActiveWpEditor(box);}); visual.addEventListener("click",function(){setActiveWpEditor(box);}); visual.addEventListener("input",function(){setActiveWpEditor(box); visual.classList.toggle("wp-editor-empty", !visual.textContent.trim());});} if(source){source.addEventListener("focus",function(){setActiveWpEditor(box);}); source.addEventListener("input",function(){setActiveWpEditor(box); if(box.classList.contains("source-mode")){} });}});
      function mediaEscape(v){return String(v||"").replace(/[&<>"]/g,function(c){return {"&":"&amp;","<":"&lt;",">":"&gt;","\"":"&quot;"}[c]||c;});}
      function mediaCardHtml(m){var title=mediaEscape(m.title||m.file||"Media"), alt=mediaEscape(m.alt||m.title||""), url=mediaEscape(m.url||""), rel=mediaEscape(m.rel||m.file||""), key=mediaEscape([m.title,m.alt,m.file].join(" ")); return `<div class="media-picker-item" data-media-item data-media-keywords="${key}"><img src="${url}" alt="${alt}" onerror="this.style.display=&quot;none&quot;"><div class="media-picker-info"><div class="media-picker-title">${title}</div><div class="text-[11px] text-slate-400 mt-1 truncate">${mediaEscape(m.basename||m.file||"")}</div><div class="media-picker-actions"><button type="button" class="media-picker-insert" data-media-insert data-media-url="${url}" data-media-rel="${rel}" data-media-alt="${alt}">Tempel</button><button type="button" class="media-picker-copy" data-copy-text="${url}">Copy</button></div></div></div>`;}
      function ensureMediaGrid(modal){var grid=modal.querySelector("[data-media-grid]"); if(!grid){var oldEmpty=modal.querySelector(".media-picker-empty"); if(oldEmpty) oldEmpty.remove(); grid=document.createElement("div"); grid.className="media-picker-grid"; grid.setAttribute("data-media-grid",""); modal.querySelector(".media-picker-body").appendChild(grid);} return grid;}
      function filterMediaItems(modal){var q=((modal.querySelector("[data-media-search]")||{}).value||"").toLowerCase().trim(); modal.querySelectorAll("[data-media-item]").forEach(function(item){var hay=(item.getAttribute("data-media-keywords")||"").toLowerCase(); item.style.display=(!q||hay.indexOf(q)>=0)?"":"none";});}
      function refreshMediaPicker(){var modal=document.getElementById("mediaPickerModal"); if(!modal) return; var url=modal.getAttribute("data-media-json-url"); if(!url) return; var grid=ensureMediaGrid(modal); grid.innerHTML=`<div class="media-picker-empty">Memuat data media terbaru...</div>`; fetch(url,{headers:{"X-Requested-With":"XMLHttpRequest"},cache:"no-store"}).then(function(r){return r.json();}).then(function(data){var items=(data&&data.items)||[]; if(!items.length){grid.innerHTML=`<div class="media-picker-empty">Belum ada media aktif. Upload dulu di halaman Media Library, lalu klik Muat Ulang Media.</div>`; return;} grid.innerHTML=items.map(mediaCardHtml).join(""); filterMediaItems(modal); activateAdminIcons();}).catch(function(){grid.innerHTML=`<div class="media-picker-empty">Media belum bisa dimuat ulang. Pastikan halaman Media Library sudah selesai upload, lalu coba lagi.</div>`;});}
      function openMediaPicker(targetBox,targetInput){ activeMediaTargetInput=targetInput||null; if(!activeMediaTargetInput) setActiveWpEditor(targetBox||activeWpEditor); var modal=document.getElementById("mediaPickerModal"); if(modal){modal.classList.add("show"); var title=modal.querySelector("[data-media-modal-note]"); if(title){title.textContent=activeMediaTargetInput?"Pilih gambar untuk dijadikan gambar utama artikel.":"Pilih gambar, lalu klik Tempel ke Artikel. Data media otomatis dimuat ulang tanpa refresh artikel.";} refreshMediaPicker(); var search=modal.querySelector("[data-media-search]"); if(search){setTimeout(function(){search.focus();},80);} } else { window.open("'.admin_base('media-library').'","_blank"); } }
      function closeMediaPicker(){var modal=document.getElementById("mediaPickerModal"); if(modal) modal.classList.remove("show"); activeMediaTargetInput=null;}
      function wpMediaHtml(kind, url, alt){ url=String(url||"").replace(/"/g,""); alt=String(alt||"").replace(/"/g,""); if(kind==="video"){return "<div class=\"pazar-media pazar-video pazar-align-center pazar-width-full\"><iframe src=\""+url+"\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen loading=\"lazy\"></iframe></div>";} return "<p class=\"pazar-media pazar-align-center pazar-width-full\"><img src=\""+url+"\" alt=\""+alt+"\"></p>"; }
      function insertHtmlIntoEditor(box, html){ var source=box.querySelector(".wp-editor-source"), visual=box.querySelector(".wp-editor-visual"); if(box.classList.contains("source-mode")&&source){ source.value += (source.value?"\n":"") + html; source.dispatchEvent(new Event("input",{bubbles:true})); } else if(visual){ visual.focus(); document.execCommand("insertHTML",false,html); visual.classList.remove("wp-editor-empty"); } wpSyncOne(box,true); }
      function insertMediaIntoEditor(url, alt, rel){ if(activeMediaTargetInput){ var inp=document.getElementById(activeMediaTargetInput); if(inp){ inp.value=rel||url; inp.dispatchEvent(new Event("input",{bubbles:true})); var img=document.getElementById("preview_"+activeMediaTargetInput); if(img){ img.src=url; img.style.display="block"; } } closeMediaPicker(); updateBlogSeo(); return; } var box=activeWpEditor||document.querySelector(".wp-editor"); if(!box||!url) return; insertHtmlIntoEditor(box, wpMediaHtml("image", url, alt)); closeMediaPicker(); }
      function selectedMediaBox(box){ var visual=box.querySelector(".wp-editor-visual"); if(!visual) return null; var sel=window.getSelection&&window.getSelection(); var node=sel&&sel.rangeCount?sel.anchorNode:null; if(node&&node.nodeType===3) node=node.parentElement; var media=node&&node.closest?node.closest(".pazar-media, img, iframe"):null; if(!media||!visual.contains(media)) media=visual.querySelector(".pazar-media:last-of-type, img:last-of-type, iframe:last-of-type"); if(!media) return null; if(media.matches("img,iframe")){ var p=media.closest(".pazar-media"); if(p) media=p; else { var wrap=document.createElement(media.tagName.toLowerCase()==="iframe"?"div":"p"); wrap.className="pazar-media pazar-align-center pazar-width-full"+(media.tagName.toLowerCase()==="iframe"?" pazar-video":""); media.parentNode.insertBefore(wrap, media); wrap.appendChild(media); media=wrap; } } return media; }
      function applyMediaClass(box, prefix, cls){ var m=selectedMediaBox(box); if(!m){alert("Klik gambar/video di editor dulu, lalu pilih ukuran atau posisi."); return;} Array.from(m.classList).forEach(function(c){ if(c.indexOf(prefix)===0) m.classList.remove(c); }); m.classList.add(cls); wpSyncOne(box,true); }
      document.addEventListener("click",function(e){
        var tab=e.target.closest(".wp-editor-tab");
        if(tab){var box=tab.closest(".wp-editor"); if(!box) return; var mode=tab.dataset.mode; if(mode==="source"){wpSyncOne(box,true); box.classList.add("source-mode");}else{wpSyncOne(box,false); box.classList.remove("source-mode");} box.querySelectorAll(".wp-editor-tab").forEach(function(t){t.classList.toggle("active", t.dataset.mode===mode);}); return;}
        var b=e.target.closest(".mini-toolbar button"); if(!b) return; var box=b.closest(".wp-editor"); if(!box) return; setActiveWpEditor(box); var source=box.querySelector(".wp-editor-source"), visual=box.querySelector(".wp-editor-visual"), cmd=b.dataset.cmd, val=b.dataset.value||null;
        if(cmd==="media"){ openMediaPicker(box); return; }
        if(cmd==="mediaWidth"){ applyMediaClass(box,"pazar-width-",val); return; }
        if(cmd==="mediaAlign"){ applyMediaClass(box,"pazar-align-",val); return; }
        if(box.classList.contains("source-mode")){ if(!source) return; source.focus(); return; }
        if(!visual) return; visual.focus();
        if(cmd==="createLink"){val=prompt("Masukkan URL link:","https://"); if(!val) return;}
        if(cmd==="insertImage"){val=prompt("Masukkan URL gambar:","https://"); if(!val) return; insertHtmlIntoEditor(box, wpMediaHtml("image", val, "")); return;}
        if(cmd==="youtube"){val=prompt("Masukkan URL YouTube:","https://www.youtube.com/watch?v="); if(!val) return; val=wpYoutubeEmbed(val); insertHtmlIntoEditor(box, wpMediaHtml("video", val, "")); return;}
        if(cmd==="hr"){document.execCommand("insertHTML",false,"<hr>"); return;}
        if(cmd==="formatBlock") document.execCommand(cmd,false,val); else if(cmd) document.execCommand(cmd,false,val);
      });
      document.addEventListener("click",function(e){
        var mpo=e.target.closest("[data-media-picker-open]"); if(mpo){ e.preventDefault(); openMediaPicker(activeWpEditor, mpo.getAttribute("data-media-target")||null); return; }
        if(e.target.closest("[data-media-close]") || e.target.classList.contains("media-picker-backdrop")){ e.preventDefault(); closeMediaPicker(); return; }
        if(e.target.closest("[data-media-refresh]")){ e.preventDefault(); refreshMediaPicker(); return; }
        var clr=e.target.closest("[data-clear-featured]"); if(clr){ e.preventDefault(); var id=clr.getAttribute("data-clear-featured"); var inp=document.getElementById(id); if(inp){inp.value="";} var img=document.getElementById("preview_"+id); if(img){img.removeAttribute("src"); img.style.display="none";} updateBlogSeo(); return; }
        var ins=e.target.closest("[data-media-insert]"); if(ins){ e.preventDefault(); insertMediaIntoEditor(ins.getAttribute("data-media-url"), ins.getAttribute("data-media-alt")||"", ins.getAttribute("data-media-rel")||""); return; }
      });
      document.addEventListener("input",function(e){
        if(!e.target.matches("[data-media-search]")) return; var modal=e.target.closest("#mediaPickerModal")||document; filterMediaItems(modal);
      });
      document.addEventListener("submit",function(e){document.querySelectorAll(".wp-editor").forEach(function(box){wpSyncOne(box,true);});},true);
      function slugifyAdmin(v){return (v||"").toString().normalize("NFD").replace(/[\u0300-\u036f]/g,"").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"");}
      var titleSrc=document.querySelector("[name$=\"title_id\"], [name$=\"name_id\"], [name*=\"judul\"], [name*=\"nama\"]"), slugField=document.querySelector("[data-slug-field]"); if(titleSrc && slugField && !slugField.value){ titleSrc.addEventListener("input",function(){ if(!slugField.dataset.touched) slugField.value=slugifyAdmin(titleSrc.value); }); slugField.addEventListener("input",function(){slugField.dataset.touched="1";}); }
      document.querySelectorAll(".upload-input").forEach(function(inp){inp.addEventListener("change",function(){var img=document.getElementById(inp.dataset.preview), f=inp.files&&inp.files[0]; if(!img||!f) return; if(f.type && f.type.indexOf("image/")===0){ img.src=URL.createObjectURL(f); img.style.display="block"; }});});
      function plainFromEditor(name){var visual=document.getElementById(name+"_visual"), src=document.querySelector("[name=\""+name+"\"]"); var html=visual?visual.innerText:(src?src.value:""); return (html||"").replace(/\s+/g," ").trim();}
      function setVal(name,val){var el=document.querySelector("[name=\""+name+"\"]"); if(el){el.value=val; el.dispatchEvent(new Event("input",{bubbles:true}));}}
      function updateCounters(){document.querySelectorAll("[data-count-for]").forEach(function(c){var name=c.getAttribute("data-count-for"), txt=plainFromEditor(name), n=txt.length; c.querySelector("span").textContent=n+" karakter"; c.classList.toggle("good", n>=300); c.classList.toggle("warn", n>0&&n<300); c.classList.toggle("bad", n===0);});}
      function updateBlogSeo(){var title=(document.querySelector("[name=\"b_meta_title_id\"]")||{}).value || (document.querySelector("[name=\"b_title_id\"]")||{}).value || "Judul artikel akan tampil di sini"; var slug=(document.querySelector("[name=\"b_slug_id\"]")||{}).value || slugifyAdmin((document.querySelector("[name=\"b_title_id\"]")||{}).value||"contoh-slug"); var desc=(document.querySelector("[name=\"b_meta_description_id\"]")||{}).value || plainFromEditor("b_excerpt_id") || "Meta description atau ringkasan artikel akan tampil di sini."; var t=document.getElementById("seoPreviewTitle"), u=document.getElementById("seoPreviewUrl"), d=document.getElementById("seoPreviewDesc"); if(t)t.textContent=title.substring(0,70); if(u)u.textContent="/id/blog/"+(slug||"contoh-slug"); if(d)d.textContent=desc.substring(0,165); document.querySelectorAll(".blog-checklist [data-check]").forEach(function(row){var k=row.getAttribute("data-check"), ok=false; if(k==="title") ok=!!(document.querySelector("[name=\"b_title_id\"]")||{}).value; if(k==="excerpt") ok=plainFromEditor("b_excerpt_id").length>40; if(k==="content") ok=plainFromEditor("b_content_id").length>=300; if(k==="image"){ var im=document.querySelector("[name=\"b_image\"]"); ok=!!((im&&im.value) || (document.querySelector("[name=\"existing_b_image\"]")||{}).value || ((im&&im.files)||[]).length); } if(k==="seo") ok=!!(document.querySelector("[name=\"b_meta_title_id\"]")||{}).value && !!(document.querySelector("[name=\"b_meta_description_id\"]")||{}).value; row.classList.toggle("ok",ok);}); updateCounters();}
      document.addEventListener("input",function(e){ if(e.target.matches("[name^=\"b_\"], .wp-editor-visual")) updateBlogSeo(); });
      document.addEventListener("click",function(e){var act=e.target.closest("[data-blog-action]"); if(!act) return; var a=act.getAttribute("data-blog-action"); if(a==="copy-title-seo") setVal("b_meta_title_id", ((document.querySelector("[name=\"b_title_id\"]")||{}).value||"").substring(0,70)); if(a==="copy-excerpt-seo") setVal("b_meta_description_id", plainFromEditor("b_excerpt_id").substring(0,160)); if(a==="generate-excerpt") setVal("b_excerpt_id", plainFromEditor("b_content_id").substring(0,180)); updateBlogSeo();});
      setTimeout(updateBlogSeo,150);
      (function(){
        if(location.href.indexOf("table=pazar_blog")<0) return;
        var key="pazar_blog_draft:"+location.pathname+location.search;
        var restored=false;
        function collectDraft(){document.querySelectorAll(".wp-editor").forEach(function(box){wpSyncOne(box,true);}); var data={t:Date.now(),fields:{}}; document.querySelectorAll("input[name], textarea[name], select[name]").forEach(function(el){ if(el.type==="file" || el.name.indexOf("existing_")===0) return; data.fields[el.name]=el.value; }); localStorage.setItem(key,JSON.stringify(data));}
        function restoreDraft(){var raw=localStorage.getItem(key); if(!raw) return; var data=null; try{data=JSON.parse(raw);}catch(e){return;} if(!data||!data.fields) return; var age=Math.round((Date.now()-(data.t||0))/60000); var ok=confirm("Ditemukan draft lokal artikel yang belum disimpan"+(age>0?" sekitar "+age+" menit lalu":"")+". Pulihkan isi form ini?"); if(!ok) return; Object.keys(data.fields).forEach(function(name){ var el=document.querySelector("[name=\""+CSS.escape(name)+"\"]"); if(el){el.value=data.fields[name]; el.dispatchEvent(new Event("input",{bubbles:true}));} }); document.querySelectorAll(".wp-editor").forEach(function(box){wpSyncOne(box,false);}); restored=true; updateBlogSeo();}
        setTimeout(restoreDraft,350);
        var timer=null; document.addEventListener("input",function(){clearTimeout(timer); timer=setTimeout(collectDraft,600);},true); document.addEventListener("click",function(e){if(e.target.closest(".mini-toolbar button,[data-media-insert],[data-clear-featured]")){setTimeout(collectDraft,300);}},true);
        document.addEventListener("submit",function(){localStorage.removeItem(key);},true);
      })();
      function activateAdminIcons(){ if(window.lucide){lucide.createIcons();} else {document.querySelectorAll("[data-lucide]").forEach(function(i){i.classList.add("lucide-fallback");});} } activateAdminIcons(); setTimeout(activateAdminIcons,400); window.addEventListener("load",activateAdminIcons);
    })();
    </script></body></html>'; exit;
}

function admin_field_label($field){
    $human = [
        'p_id_product_category'=>'Kategori Produk',
        'pd_id_product'=>'Produk',
        'rd_id_recipe'=>'Resep',
        'rcj_id_recipe'=>'Resep',
        'rcj_id_category'=>'Kategori Resep',
        'b_category_id'=>'Kategori Blog',
        'v_department_id'=>'Departemen',
        'v_experience_id'=>'Pengalaman',
        'u_role'=>'Role User',
        'u_is_active'=>'Status Aktif',
        'p_is_active'=>'Status Produk',
        'r_is_active'=>'Status Resep',
        'b_is_active'=>'Status Artikel',
        'b_is_featured'=>'Artikel Pilihan',
        'b_status'=>'Status Publish',
        'b_publish_at'=>'Tanggal Publish',
        'bcmt_blog_id'=>'Artikel Blog',
        'bcmt_name'=>'Nama Komentator',
        'bcmt_email'=>'Email Komentator',
        'bcmt_message'=>'Isi Komentar',
        'bcmt_status'=>'Status Komentar',
    ];
    $f = strtolower($field);
    if(isset($human[$f])) return $human[$f];
    $labels = [
        'title'=>'Judul','name'=>'Nama','description'=>'Deskripsi','desc'=>'Deskripsi','longdesc'=>'Deskripsi Lengkap','content'=>'Konten','image'=>'Gambar','icon'=>'Ikon','slug'=>'Slug','url'=>'URL','link'=>'Link','category'=>'Kategori','department'=>'Departemen','experience'=>'Pengalaman','product'=>'Produk','recipe'=>'Resep','status'=>'Status','type'=>'Tipe','weight'=>'Berat','net_weight'=>'Berat Bersih','is_active'=>'Status Aktif','is_featured'=>'Ditampilkan','created_at'=>'Dibuat','updated_at'=>'Diubah'
    ];
    foreach($labels as $k=>$v){ if($f===$k || str_ends_with($f,'_'.$k)) return $v; }
    $f = preg_replace('/^[a-z0-9]+_/', '', $field);
    $f = preg_replace('/(^id_|_id$)/', '', $f);
    return ucwords(str_replace('_',' ', $f));
}
function admin_is_audit_field($field){ return preg_match('~(^|_)(created_at|updated_at|deleted_at|created_by|updated_by|deleted_by)$~i',$field); }
function admin_is_file_field($field){ return preg_match('~(image|icon|photo|picture|profile|file|catalog|pdf)~i',$field); }
function admin_upload_folder($table,$field){
    if(str_contains($table,'blog')) return 'blog';
    if(str_contains($table,'media')) return 'media';
    if(str_contains($table,'recipe')) return 'recipes';
    if(str_contains($table,'product_category')) return 'product_categories';
    if(str_contains($table,'product')) return 'products';
    if(str_contains($table,'header')) return 'headers';
    if(str_contains($table,'footer')) return 'footers';
    if(str_contains($table,'certification')) return 'certifications';
    if(str_contains($table,'history')) return 'histories';
    if(str_contains($table,'career')) return 'careers';
    if(str_contains($table,'popup')) return 'popups';
    return 'uploads';
}
function admin_save_uploaded_file($table,$field){
    if(empty($_FILES[$field]) || ($_FILES[$field]['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) return null;
    $name = $_FILES[$field]['name'] ?? 'file';
    $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
    $allowed = ['jpg','jpeg','png','webp','gif','svg','pdf'];
    if(!in_array($ext,$allowed,true)) return null;
    $folder = admin_upload_folder($table,$field);
    $dir = PUBLICPATH.'storage/'.$folder;
    if(!is_dir($dir)) @mkdir($dir,0775,true);
    $safeBase = slugify(pathinfo($name,PATHINFO_FILENAME));
    $file = date('YmdHis').'-'.substr(sha1($name.microtime(true)),0,6).'-'.$safeBase.'.'.$ext;
    $dest = $dir.'/'.$file;
    if(!move_uploaded_file($_FILES[$field]['tmp_name'],$dest)) return null;
    admin_optimize_image_file($dest,$ext,1600,82);
    admin_register_media($folder.'/'.$file, $table, $field, $dest);
    return $folder.'/'.$file;
}
function admin_register_media($rel,$table,$field,$abs=''){
    if(!db()) return; pazar_bootstrap_v16();
    $mime = $abs && is_file($abs) ? (mime_content_type($abs) ?: '') : '';
    $size = $abs && is_file($abs) ? filesize($abs) : 0; $w=0; $h=0;
    if($abs && is_file($abs) && pazar_is_image_path($abs) && function_exists('getimagesize')){ $info=@getimagesize($abs); if($info){$w=(int)$info[0];$h=(int)$info[1];} }
    try{ rows("INSERT INTO pazar_media_library (m_title,m_file,m_mime,m_size,m_width,m_height,m_used_for,m_is_active,m_created_at) VALUES (?,?,?,?,?,?,?,?,NOW())", [basename($rel),$rel,$mime,$size,$w,$h,$table.'.'.$field,1]); }catch(Exception $e){}
}
function admin_short_value($field,$value,$table=''){
    $value=(string)$value;
    $relLabel = $table ? admin_relation_value_label($table,$field,$value) : null;
    if($relLabel !== null){ return '<span class="badge badge-soft">'.e($relLabel).'</span>'; }
    if(admin_is_file_field($field) && $value){
        $url = pazar_file_url($value,$table,$field);
        if(pazar_is_image_path($value)) return '<a href="'.e($url).'" target="_blank" class="admin-thumb-link"><img class="admin-thumb" src="'.e($url).'" alt="'.e(basename($value)).'" onerror="this.style.display=\'none\';this.nextElementSibling.style.display=\'inline-flex\'"><span class="badge" style="display:none">File</span></a><div class="text-xs text-slate-300 mt-1">'.e(basename($value)).'</div>';
        return '<span class="badge">File</span> '.e(basename($value));
    }
    if(strlen(strip_tags($value))>90) return e(mb_substr(strip_tags($value),0,90).'…');
    if($value==='1') return '<span class="badge">Aktif / Ya</span>';
    if($value==='0') return '<span class="badge">Tidak</span>';
    return e($value);
}
function admin_card($label,$value,$icon,$color){
    echo '<div class="bg-slate-800 rounded-lg shadow-md border-l-4 '.$color.' p-6"><div class="flex items-center"><div class="p-3 mr-4 rounded-full bg-slate-700 bg-opacity-70"><i data-lucide="'.$icon.'" class="w-6 h-6"></i></div><div><p class="text-sm font-medium text-slate-400">'.e($label).'</p><p class="text-lg font-semibold text-white">'.e($value).'</p></div></div></div>';
}
function admin_dashboard(){
    admin_shell_start('Dashboard');
    if(($_GET['regen'] ?? '')==='1') echo '<div class="mb-5 p-4 rounded-xl border border-emerald-700 bg-emerald-950/40 text-emerald-100">Semua kolom English berhasil dibuat ulang dari konten Indonesia.</div>';
    if(!empty($_SESSION['translate_flash'])){ echo '<div class="mb-5 p-4 rounded-xl border border-sky-700 bg-sky-950/40 text-sky-100">'.e($_SESSION['translate_flash']).'</div>'; unset($_SESSION['translate_flash']); }
    echo '<div class="mb-5 p-4 rounded-xl border border-cyan-700 bg-cyan-950/30 text-cyan-100"><b>Auto English aktif.</b> Provider: <b>'.e(strtoupper(pazar_translation_provider())).'</b>. Generate massal sekarang bertahap supaya tidak muter terus: <a class="underline font-bold" href="'.admin_base('manage?action=regenerate_english_async').'">Generate ulang English bertahap</a>. Cek API: <a class="underline font-bold" href="'.admin_base('manage?action=test_gemini').'">Test Gemini</a>. Tools: <a class="underline font-bold" href="'.admin_base('manage?action=generate_sitemap').'">Generate Sitemap</a> · <a class="underline font-bold" href="'.admin_base('manage?action=generate_robots').'">Generate Robots</a> · <a class="underline font-bold" href="'.admin_base('manage?action=backup_database').'">Backup Database</a>.</div>';
    echo '<div class="grid grid-cols-1 gap-6 md:grid-cols-2 xl:grid-cols-4">';
    admin_card('Total Products', table_count_safe('pazar_product'), 'package', 'border-purple-400');
    admin_card('Active Products', table_count_safe('pazar_product','p_is_active=1'), 'check-circle', 'border-blue-400');
    admin_card('Total Recipes', table_count_safe('pazar_recipe'), 'clipboard-list', 'border-yellow-400');
    admin_card('Total Blog Posts', table_count_safe('pazar_blog'), 'newspaper', 'border-orange-400');
    admin_card('Active Vacancies', table_count_safe('career_vacancies','v_is_active=1'), 'shield-check', 'border-green-400');
    echo '</div>';
    $ts=admin_dashboard_translation_summary();
    echo '<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mt-8">';
    echo '<div class="admin-card p-5"><h2 class="text-lg font-semibold mb-4">Status Translate English</h2><div class="space-y-3 text-sm"><div>'.admin_badge('ok','OK').' <b>'.e($ts['ok']).'</b> data siap English</div><div>'.admin_badge('warn','Cek manual').' <b>'.e($ts['warn']).'</b> data perlu dicek</div><div>'.admin_badge('empty','Kosong').' <b>'.e($ts['empty']).'</b> data belum punya English</div><div class="text-slate-400 pt-2">Total dicek: '.e($ts['total']).' data</div></div></div>';
    echo '<div class="admin-card p-5 lg:col-span-2"><h2 class="text-lg font-semibold mb-4">Shortcut Cepat</h2><div class="quick-grid"><a class="quick-card" href="'.admin_base('manage?table=pazar_product').'">+ Kelola Produk</a><a class="quick-card" href="'.admin_base('manage?table=pazar_recipe').'">+ Kelola Resep</a><a class="quick-card" href="'.admin_base('manage?table=pazar_blog').'">+ Tulis Blog</a><a class="quick-card" href="'.admin_base('media-library').'">+ Media Library</a><a class="quick-card" href="'.admin_base('manage?table=pazar_headers').'">+ Header / Banner</a><a class="quick-card" href="'.admin_base('manage?table=career_vacancies').'">+ Lowongan</a><a class="quick-card" href="'.admin_base('manage?action=regenerate_english_async').'">Generate English Bertahap</a><a class="quick-card" href="'.admin_base('manage?action=test_gemini').'">Test Gemini</a></div></div>';
    echo '</div>';
    echo '<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mt-8">';
    echo '<div class="admin-card p-5"><h2 class="text-lg font-semibold mb-4">Konten Terbaru</h2>';
    $recent=[]; foreach(['pazar_product'=>'Produk','pazar_recipe'=>'Resep','pazar_blog'=>'Blog','career_vacancies'=>'Lowongan'] as $t=>$lbl){ $cols=rows("SHOW COLUMNS FROM ".admin_ident($t)); if(!$cols) continue; $pk=$cols[0]->Field; $title=admin_title_field($cols); $rs=rows("SELECT * FROM ".admin_ident($t)." ORDER BY ".admin_ident($pk)." DESC LIMIT 3"); foreach($rs as $r){ $recent[]=['table'=>$t,'label'=>$lbl,'title'=>$r->$title ?? ('#'.$r->$pk),'id'=>$r->$pk]; } }
    if(!$recent) echo '<p class="text-slate-400 text-sm">Belum ada data terbaru.</p>'; else foreach(array_slice($recent,0,8) as $r){ echo '<div class="activity-item"><b>'.e($r['label']).'</b> — '.e($r['title']).'<div><a class="text-sky-300 text-sm" href="'.admin_base('manage?table='.$r['table'].'&edit='.$r['id']).'">Edit data</a></div></div>'; }
    echo '</div><div class="admin-card p-5"><h2 class="text-lg font-semibold mb-4">Log Aktivitas Admin</h2>';
    $acts=admin_recent_activity(8); if(!$acts) echo '<p class="text-slate-400 text-sm">Belum ada aktivitas tercatat.</p>'; else foreach($acts as $a){ echo '<div class="activity-item"><div><b>'.e($a['action']).'</b> '.e($a['table']).' #'.e($a['record']).'</div><div class="text-xs text-slate-400">'.e($a['user']).' • '.e($a['time']).' '.($a['note']?'• '.e($a['note']):'').'</div></div>'; }
    echo '</div></div>';
    echo '<div class="grid grid-cols-1 gap-6 md:grid-cols-2 xl:grid-cols-4 mt-8">';
    admin_card('Certifications', table_count_safe('pazar_certifications'), 'check-circle', 'border-emerald-400');
    admin_card('Why Pazar', table_count_safe('pazar_why_pazar'), 'tag', 'border-amber-400');
    admin_card('Product Categories', table_count_safe('pazar_product_category'), 'tags', 'border-teal-400');
    admin_card('Recipe Categories', table_count_safe('pazar_recipe_category'), 'tag', 'border-lime-400');
    echo '</div>';
    admin_shell_end();
}

function admin_login(){
    if($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['email'])){
        $u=row("SELECT * FROM login_users WHERE u_email=? AND u_is_active=1",[$_POST['email']]);
        if($u && password_verify($_POST['password']??'', $u->u_password)){ $_SESSION['admin']=$u; header('Location: '.admin_base('dashboard')); exit; }
        $err='Email atau password salah';
    }
    echo '<!doctype html><html lang="en" class="dark"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>Login - Pazar Website Admin</title><script src="https://cdn.tailwindcss.com"></script><script>tailwind.config={darkMode:"class",theme:{extend:{colors:{accent:"#BF161C","gray-custom":"#E0FBFC","bg-dark":"#253237"}}}}</script></head><body class="bg-bg-dark text-gray-custom min-h-screen flex items-center justify-center p-4"><form method="post" class="w-full max-w-md p-7 bg-slate-800 border border-slate-700 rounded-xl shadow-xl"><div class="text-center mb-6"><img src="'.asset('img/Web/Logo.webp').'" class="h-16 mx-auto mb-4"><h1 class="text-2xl font-bold">Pazar Website Admin Login</h1><p class="text-sm text-slate-400 mt-1">Restricted CMS Area</p></div>'.(!empty($err)?'<div class="p-3 mb-4 rounded bg-red-900/70 border-l-4 border-red-500 text-red-100">'.$err.'</div>':'').'<label class="block mb-2 text-sm">Email</label><input type="email" name="email" required class="w-full p-3 rounded-lg bg-gray-50 text-gray-900 mb-4" placeholder="name@company.com"><label class="block mb-2 text-sm">Password</label><input type="password" name="password" required class="w-full p-3 rounded-lg bg-gray-50 text-gray-900 mb-6" placeholder="••••••••"><button class="w-full px-5 py-3 text-white bg-accent hover:bg-red-800 rounded-lg font-semibold">Log in</button></form></body></html>'; exit;
}

function admin_translation_pairs($cols){
    $names = array_map(fn($c)=>$c->Field, $cols);
    $set = array_flip($names); $pairs=[];
    foreach($names as $name){
        if(str_ends_with($name,'_id')){
            $en = substr($name,0,-3).'_en';
            if(isset($set[$en])) $pairs[$name]=$en;
        }
    }
    return $pairs;
}
function admin_is_translation_en_field($field,$pairs){ return in_array($field, $pairs, true); }
function admin_translation_base_label($field){
    $x = preg_replace('/_(id|en)$/','',$field);
    $x = preg_replace('/^[a-z]{1,4}_/','',$x);
    $map=['title'=>'Judul','description'=>'Deskripsi','desc'=>'Deskripsi','longdesc'=>'Deskripsi Lengkap','content'=>'Konten','label'=>'Label','name'=>'Nama','product'=>'Produk','meta_title'=>'Meta Title','meta_description'=>'Meta Description'];
    return $map[$x] ?? ucwords(str_replace('_',' ', $x));
}
function admin_enum_options_from_type($type){
    if(!preg_match("~^enum\((.*)\)$~i", trim($type), $m)) return [];
    $raw=$m[1]; $out=[]; $cur=''; $q=false; $len=strlen($raw);
    for($i=0;$i<$len;$i++){
        $ch=$raw[$i];
        if($ch==="'" && ($i===0 || $raw[$i-1] !== '\\')){ $q=!$q; continue; }
        if($ch===',' && !$q){ $out[]=stripslashes($cur); $cur=''; continue; }
        $cur.=$ch;
    }
    if($cur!=='') $out[]=stripslashes($cur);
    return array_map(fn($x)=>trim($x), $out);
}
function admin_relation_definition($table,$field){
    static $cache=[]; $key=$table.'.'.$field; if(array_key_exists($key,$cache)) return $cache[$key];
    $manual = [
        'pazar_product.p_id_product_category'=>['table'=>'pazar_product_category','pk'=>'pc_id','title'=>'pc_title_id','label'=>'Kategori Produk'],
        'pazar_product_detail.pd_id_product'=>['table'=>'pazar_product','pk'=>'p_id','title'=>'p_title_id','label'=>'Produk'],
        'pazar_recipe_detail.rd_id_recipe'=>['table'=>'pazar_recipe','pk'=>'r_id','title'=>'r_title_id','label'=>'Resep'],
        'pazar_recipe_category_junction.rcj_id_recipe'=>['table'=>'pazar_recipe','pk'=>'r_id','title'=>'r_title_id','label'=>'Resep'],
        'pazar_recipe_category_junction.rcj_id_category'=>['table'=>'pazar_recipe_category','pk'=>'rc_id','title'=>'rc_title_id','label'=>'Kategori Resep'],
        'pazar_blog.b_category_id'=>['table'=>'pazar_blog_category','pk'=>'bc_id','title'=>'bc_title_id','label'=>'Kategori Blog'],
        'pazar_blog_comment.bcmt_blog_id'=>['table'=>'pazar_blog','pk'=>'b_id','title'=>'b_title_id','label'=>'Artikel Blog'],
        'career_vacancies.v_department_id'=>['table'=>'career_departments','pk'=>'da_id','title'=>'da_title_id','label'=>'Departemen'],
        'career_vacancies.v_experience_id'=>['table'=>'career_experiences','pk'=>'ex_id','title'=>'ex_title_id','label'=>'Pengalaman'],
    ];
    if(isset($manual[$key])) return $cache[$key]=$manual[$key];
    try{
        $create=rows('SHOW CREATE TABLE '.admin_ident($table));
        $sql=$create[0]->{'Create Table'} ?? '';
        if($sql && preg_match('~FOREIGN KEY \(`'.preg_quote($field,'~').'`\) REFERENCES `([^`]+)` \(`([^`]+)`\)~', $sql, $m)){
            $rt=$m[1]; $rpk=$m[2]; $rcols=rows('SHOW COLUMNS FROM '.admin_ident($rt));
            if($rcols){
                $title=admin_title_field($rcols);
                return $cache[$key]=['table'=>$rt,'pk'=>$rpk,'title'=>$title,'label'=>admin_field_label($field)];
            }
        }
    }catch(Throwable $e){}
    return $cache[$key]=null;
}
function admin_relation_options($def){
    if(!$def) return [];
    $where='';
    try{
        $cols=array_map(fn($c)=>$c->Field, rows('SHOW COLUMNS FROM '.admin_ident($def['table'])));
        foreach($cols as $c){ if(preg_match('~(^|_)is_active$~',$c)){ $where=' WHERE '.admin_ident($c).'=1'; break; } }
        $sql='SELECT '.admin_ident($def['pk']).' AS rel_id, '.admin_ident($def['title']).' AS rel_title FROM '.admin_ident($def['table']).$where.' ORDER BY '.admin_ident($def['title']).' ASC LIMIT 1000';
        return rows($sql);
    }catch(Throwable $e){ return []; }
}
function admin_relation_value_label($table,$field,$value){
    $def=admin_relation_definition($table,$field); if(!$def || $value==='' || $value===null) return null;
    try{
        $r=row('SELECT '.admin_ident($def['title']).' AS title FROM '.admin_ident($def['table']).' WHERE '.admin_ident($def['pk']).'=? LIMIT 1', [$value]);
        if($r && trim((string)$r->title)!=='') return $r->title;
    }catch(Throwable $e){}
    return null;
}
function admin_render_relation_select($table,$field,$val,$def){
    $safe=e($field); $opts=admin_relation_options($def);
    echo '<select id="'.$safe.'" name="'.$safe.'" class="admin-select relation-select"><option value="">- Pilih '.e($def['label'] ?? admin_field_label($field)).' -</option>';
    foreach($opts as $opt){ $cv=$opt->rel_id ?? ''; $ct=$opt->rel_title ?? ('#'.$cv); echo '<option value="'.e($cv).'" '.(((string)$val===(string)$cv)?'selected':'').'>'.e($ct).'</option>'; }
    echo '</select><div class="admin-help">Pilih berdasarkan nama, bukan angka ID. Nilai teknis akan disimpan otomatis oleh sistem.</div>';
}
function admin_render_field($t,$c,$pk,$edit,$pairs,$advanced=false){
    $rawField=$c->Field;
    if($rawField===$pk) return;
    $val=$edit->{$rawField}??''; $field=e($rawField); $type=strtolower($c->Type);
    $isText=str_contains($type,'text');
    $isBool=(str_contains($rawField,'is_active')||str_contains($rawField,'is_featured')||str_contains($rawField,'show')||str_contains($type,'tinyint(1)'));
    $isFile=admin_is_file_field($rawField); $isAudit=admin_is_audit_field($rawField);
    $isIdTranslation = isset($pairs[$rawField]);
    $isEnTranslation = admin_is_translation_en_field($rawField,$pairs);
    $isSlug = preg_match('~(^|_)slug(_id|_en)?$~i',$rawField);
    $relation = (!$isIdTranslation && !$isEnTranslation) ? admin_relation_definition($t,$rawField) : null;
    $label = $relation ? ($relation['label'] ?? admin_field_label($rawField)) : ($isIdTranslation || $isEnTranslation ? admin_translation_base_label($rawField) : admin_field_label($rawField));
    $badge = $isIdTranslation ? '<span class="ml-2 text-[11px] px-2 py-0.5 rounded-full bg-emerald-900/60 text-emerald-200">Bahasa Indonesia</span>' : ($isEnTranslation ? '<span class="ml-2 text-[11px] px-2 py-0.5 rounded-full bg-sky-900/60 text-sky-200">English otomatis</span>' : ($relation ? '<span class="ml-2 text-[11px] px-2 py-0.5 rounded-full bg-indigo-900/60 text-indigo-100">Dropdown</span>' : ''));
    $full = ($isText || $isFile) ? ' full' : '';
    $dataRole = $isIdTranslation ? ' data-id-source="1"' : '';
    $slugRole = $isSlug ? ' data-slug-field="1"' : '';
    echo '<div class="admin-field'.$full.($isAudit?' hidden-audit':'').'"><label class="admin-label" for="'.$field.'">'.e($label).' '.$badge.'</label>';
    if($isAudit){ echo '<input type="hidden" name="'.$field.'" value="'.e($val).'">'; }
    elseif($isText){
        echo '<div class="wp-editor" data-editor="'.$field.'"><div class="wp-editor-head"><div class="mini-toolbar"><button type="button" data-cmd="formatBlock" data-value="p">Paragraf</button><button type="button" data-cmd="formatBlock" data-value="h1">H1</button><button type="button" data-cmd="formatBlock" data-value="h2">H2</button><button type="button" data-cmd="formatBlock" data-value="h3">H3</button><button type="button" data-cmd="bold">Bold</button><button type="button" data-cmd="italic">Italic</button><button type="button" data-cmd="formatBlock" data-value="blockquote">Quote</button><button type="button" data-cmd="insertUnorderedList">Bullet</button><button type="button" data-cmd="insertOrderedList">Number</button><button type="button" data-cmd="createLink">Link</button><button type="button" data-cmd="insertImage">Image URL</button><button type="button" data-cmd="media">Media Library</button><button type="button" data-cmd="youtube">YouTube</button><button type="button" data-cmd="mediaWidth" data-value="pazar-width-25">25%</button><button type="button" data-cmd="mediaWidth" data-value="pazar-width-50">50%</button><button type="button" data-cmd="mediaWidth" data-value="pazar-width-75">75%</button><button type="button" data-cmd="mediaWidth" data-value="pazar-width-full">Full</button><button type="button" data-cmd="mediaAlign" data-value="pazar-align-left">Kiri</button><button type="button" data-cmd="mediaAlign" data-value="pazar-align-center">Tengah</button><button type="button" data-cmd="mediaAlign" data-value="pazar-align-right">Kanan</button><button type="button" data-cmd="hr">Divider</button><button type="button" data-cmd="removeFormat">Clear</button></div><div class="wp-editor-tabs"><button type="button" class="wp-editor-tab active" data-mode="visual">Visual</button><button type="button" class="wp-editor-tab" data-mode="source">Teks/HTML</button></div></div><div class="wp-editor-body"><div id="'.$field.'_visual" class="wp-editor-visual wp-editor-empty" contenteditable="true" data-placeholder="Tulis konten di sini seperti editor WordPress Classic..."></div><textarea id="'.$field.'" name="'.$field.'" rows="9" class="admin-textarea wp-editor-source"'.$dataRole.'>'.e($val).'</textarea></div></div><div class="char-counter" data-count-for="'.$field.'"><span>0 karakter</span><span>Target artikel: minimal 300 karakter</span></div><div class="admin-help">'.($isIdTranslation?'Isi Bahasa Indonesia di mode Visual. Versi English akan dibuat otomatis saat disimpan. Gunakan tab Teks/HTML jika ingin edit kode HTML.':'Klik gambar/video di editor, lalu pilih 25%, 50%, 75%, Full, Kiri, Tengah, atau Kanan untuk mengatur ukuran dan posisi. Video YouTube otomatis responsif penuh.').'</div>';
    }
    elseif($relation){
        admin_render_relation_select($t,$rawField,$val,$relation);
    }
    elseif($rawField==='b_category_id' || preg_match('~(^|_)category_id$~i',$rawField)){
        $catTable = $rawField==='b_category_id' ? 'pazar_blog_category' : (str_contains($t,'recipe')?'pazar_recipe_category':(str_contains($t,'product')?'pazar_product_category':''));
        echo '<select id="'.$field.'" name="'.$field.'" class="admin-select"><option value="">- Pilih Kategori -</option>';
        if($catTable){
            $catCols=rows('SHOW COLUMNS FROM '.admin_ident($catTable)); $catPk=$catCols[0]->Field ?? 'id'; $catTitle=admin_title_field($catCols);
            foreach(rows('SELECT * FROM '.admin_ident($catTable).' ORDER BY '.admin_ident($catPk).' ASC') as $cat){ $cv=$cat->$catPk ?? ''; $ct=$cat->$catTitle ?? ('#'.$cv); echo '<option value="'.e($cv).'" '.(((string)$val===(string)$cv)?'selected':'').'>'.e($ct).'</option>'; }
        }
        echo '</select><div class="admin-help">Kategori membantu pengelompokan konten di halaman frontend.</div>';
    }
    elseif($rawField==='bcmt_status'){ $opts=['pending'=>'Pending - menunggu approve','approved'=>'Approved - tampil di website','spam'=>'Spam / ditolak']; echo '<select id="'.$field.'" name="'.$field.'" class="admin-select">'; foreach($opts as $ok=>$ol){ echo '<option value="'.e($ok).'" '.(((string)$val===$ok)?'selected':'').'>'.e($ol).'</option>'; } echo '</select><div class="admin-help">Komentar hanya tampil di artikel jika status Approved.</div>'; }
    elseif(preg_match('~(^|_)status$~i',$rawField)){ $opts=['draft'=>'Draft - simpan dulu','published'=>'Published - tampil di website','scheduled'=>'Scheduled - tampil sesuai jadwal','archived'=>'Archived - arsip']; echo '<select id="'.$field.'" name="'.$field.'" class="admin-select">'; foreach($opts as $ok=>$ol){ echo '<option value="'.e($ok).'" '.(((string)$val===$ok)?'selected':'').'>'.e($ol).'</option>'; } echo '</select><div class="admin-help">Draft tidak tampil di frontend. Scheduled tampil sesuai tanggal publish.</div>'; }
    elseif(preg_match('~(_at|date)$~i',$rawField) && !$isText){
        $dt=''; if($val){ $ts=strtotime((string)$val); if($ts) $dt=date('Y-m-d\TH:i',$ts); }
        echo '<input id="'.$field.'" name="'.$field.'" value="'.e($dt).'" type="datetime-local" class="admin-input"><div class="admin-help">Kosongkan jika tidak perlu jadwal khusus.</div>';
    }
    elseif($enumOpts=admin_enum_options_from_type($type)){ echo '<select id="'.$field.'" name="'.$field.'" class="admin-select"><option value="">- Pilih '.e($label).' -</option>'; foreach($enumOpts as $eo){ echo '<option value="'.e($eo).'" '.(((string)$val===(string)$eo)?'selected':'').'>'.e($eo).'</option>'; } echo '</select><div class="admin-help">Pilih salah satu opsi yang tersedia.</div>'; }
    elseif($isBool){ $checked=((string)$val==='1')?'selected':''; echo '<select id="'.$field.'" name="'.$field.'" class="admin-select"><option value="1" '.$checked.'>Aktif / Ya</option><option value="0" '.(!$checked?'selected':'').'>Nonaktif / Tidak</option></select>'; }
    elseif($isFile){
        if($t==='pazar_blog' && $rawField==='b_image'){
            $preview = $val ? pazar_file_url($val,$t,$rawField) : '';
            echo '<input type="hidden" name="existing_'.$field.'" value="'.e($val).'"><input type="hidden" id="'.$field.'" name="'.$field.'" value="'.e($val).'" data-featured-image-input>';
            echo '<div class="upload-preview-box featured-image-box"><img id="preview_'.$field.'" src="'.e($preview).'" '.(!$val?'style="display:none"':'').' onerror="this.style.display=\'none\'"><span class="text-sm text-slate-400">Preview gambar utama artikel</span></div>';
            echo '<div class="flex flex-wrap gap-2 mt-3"><button type="button" class="btn btn-success" data-media-picker-open data-media-target="'.$field.'"><i data-lucide="image" class="w-4 h-4"></i>Pilih dari Media Library</button><button type="button" class="btn btn-muted" data-clear-featured="'.$field.'">Kosongkan</button></div>';
            echo '<div class="admin-help">Gambar utama artikel diambil dari Media Library supaya link mudah dipakai ulang dan file tetap ringan/terkompres. Path saat ini: '.e($val ?: '-').'</div>';
        } else {
            echo '<input type="hidden" name="existing_'.$field.'" value="'.e($val).'"><input id="'.$field.'" name="'.$field.'" type="file" class="admin-input upload-input" data-preview="preview_'.$field.'" accept=".jpg,.jpeg,.png,.webp,.gif,.svg,.pdf"><div class="admin-help">Kosongkan jika tidak ingin mengganti file. Rekomendasi: JPG/PNG/WebP, ukuran ringan, nama file otomatis diamankan. Path lama: '.e($val ?: '-').'</div>';
            echo '<div class="upload-preview-box"><img id="preview_'.$field.'" src="'.e($val ? pazar_file_url($val,$t,$rawField) : '').'" '.(!$val?'style="display:none"':'').' onerror="this.style.display=\'none\'"><span class="text-sm text-slate-400">Preview gambar/file</span></div>';
        }
    }
    else {
        echo '<input id="'.$field.'" name="'.$field.'" value="'.e($val).'" class="admin-input'.($isSlug?' slug-input':'').'"'.$dataRole.$slugRole.'><div class="admin-help">'.($isIdTranslation?'English akan dibuat otomatis dari input ini.':($isSlug?'Slug bisa otomatis dari judul, tetap boleh diedit manual.':'')).'</div>';
    }
    echo '</div>';
}

function admin_visible_table_cols($cols,$pairs){
    return array_values(array_filter($cols, function($c) use ($pairs){ return !admin_is_audit_field($c->Field) && !admin_is_translation_en_field($c->Field,$pairs); }));
}


function admin_col_map($cols){ $m=[]; foreach($cols as $c){ $m[$c->Field]=$c; } return $m; }
function admin_render_blog_writer_form($t,$cols,$pk,$edit,$pairs){
    $m=admin_col_map($cols);
    $render=function($field) use ($m,$t,$pk,$edit,$pairs){ if(isset($m[$field])) admin_render_field($t,$m[$field],$pk,$edit,$pairs,false); };
    echo '<div class="blog-writer-hero mb-5"><h3>Editor Artikel Blog</h3><p>Buat artikel seperti WordPress Classic: tulis judul, ringkasan, konten lengkap, gambar utama, jadwal publish, dan SEO dalam satu alur yang lebih rapi. Isi Bahasa Indonesia saja, versi English tetap bisa dibuat otomatis.</p></div>';
    echo '<div class="blog-editor-layout">';
    echo '<section class="blog-editor-main">';
    echo '<div class="admin-card p-5"><h3 class="blog-panel-title"><i data-lucide="newspaper" class="w-5 h-5"></i>Konten Utama</h3><div class="admin-form-grid">';
    foreach(['b_title_id','b_slug_id','b_excerpt_id','b_content_id'] as $f){ $render($f); }
    echo '</div></div>';
    echo '<div class="admin-card p-5"><h3 class="blog-panel-title"><i data-lucide="settings-2" class="w-5 h-5"></i>SEO Google</h3><p class="text-sm text-slate-400 mb-4">Bagian ini membantu artikel lebih rapi saat tampil di Google. Bisa dikosongkan, tapi lebih bagus jika diisi.</p><div class="blog-quick-actions mb-4"><button type="button" data-blog-action="copy-title-seo">Isi Meta Title dari Judul</button><button type="button" data-blog-action="copy-excerpt-seo">Isi Meta Description dari Ringkasan</button><button type="button" data-blog-action="generate-excerpt">Buat Ringkasan dari Konten</button></div><div class="admin-form-grid">';
    foreach(['b_focus_keyword_id','b_meta_title_id','b_meta_description_id'] as $f){ $render($f); }
    echo '</div><div class="mt-5"><label class="admin-label">Preview Snippet Google</label><div class="seo-preview"><div id="seoPreviewTitle" class="seo-title">Judul artikel akan tampil di sini</div><div id="seoPreviewUrl" class="seo-url">'.e(base_url('id/blog/contoh-slug')).'</div><div id="seoPreviewDesc" class="seo-desc">Meta description atau ringkasan artikel akan tampil di sini.</div></div></div></div>';
    echo '</section>';
    echo '<aside class="blog-editor-side">';
    echo '<div class="admin-card p-5"><h3 class="blog-panel-title"><i data-lucide="save" class="w-5 h-5"></i>Publish</h3><div class="grid gap-4">';
    foreach(['b_status','b_is_active','b_is_featured','b_publish_at'] as $f){ $render($f); }
    echo '</div><div class="profile-note mt-4">Tips: gunakan <b>Draft</b> saat artikel belum final. Gunakan <b>Scheduled</b> jika ingin dijadwalkan berdasarkan tanggal publish.</div></div>';
    echo '<div class="admin-card p-5"><h3 class="blog-panel-title"><i data-lucide="book-open" class="w-5 h-5"></i>Kategori & Gambar</h3><div class="grid gap-4">';
    foreach(['b_category_id','b_image'] as $f){ $render($f); }
    echo '</div></div>';
    echo '<div class="admin-card p-5"><h3 class="blog-panel-title">Checklist Artikel</h3><div class="blog-checklist"><div data-check="title"><span>✓</span>Judul sudah diisi</div><div data-check="excerpt"><span>✓</span>Ringkasan sudah diisi</div><div data-check="content"><span>✓</span>Konten minimal 300 karakter</div><div data-check="image"><span>✓</span>Gambar utama tersedia</div><div data-check="seo"><span>✓</span>SEO title & description terisi</div></div></div>';
    echo '</aside></div>';
    $mediaRows = rows("SELECT * FROM pazar_media_library WHERE m_is_active=1 ORDER BY m_id DESC LIMIT 120");
    echo '<div id="mediaPickerModal" class="media-picker-backdrop" aria-hidden="true" data-media-json-url="'.admin_base('media-library-json').'"><div class="media-picker-box"><div class="media-picker-head"><div><h3 class="text-xl font-black flex items-center gap-2"><i data-lucide="image" class="w-5 h-5 text-emerald-300"></i>Media Library</h3><p class="text-sm text-slate-400 mt-1" data-media-modal-note>Pilih gambar, lalu klik Tempel ke Artikel. Link otomatis dimasukkan ke editor yang sedang aktif.</p></div><button type="button" class="btn btn-muted" data-media-close><i data-lucide="x" class="w-4 h-4"></i>Tutup</button></div><div class="media-picker-body"><div class="flex flex-col md:flex-row gap-3 mb-4"><input class="admin-input" data-media-search placeholder="Cari media berdasarkan judul, file, alt text..."><button type="button" class="btn btn-success" data-media-refresh><i data-lucide="refresh-cw" class="w-4 h-4"></i>Muat Ulang Media</button></div>';
    if(!$mediaRows){ echo '<div class="media-picker-empty">Belum ada media. Upload media di tab Media Library, lalu klik tombol <b>Muat Ulang Media</b> di popup ini tanpa refresh artikel.</div>'; }
    else{
        echo '<div class="media-picker-grid" data-media-grid>';
        foreach($mediaRows as $m){
            $url=pazar_file_url($m->m_file ?? '', 'pazar_media_library','m_file');
            if(!pazar_is_image_path($m->m_file ?? '')) continue;
            $title=$m->m_title ?: basename($m->m_file ?? ''); $alt=$m->m_alt_id ?: $title; $key=$title.' '.$alt.' '.($m->m_file ?? '');
            echo '<div class="media-picker-item" data-media-item data-media-keywords="'.e($key).'"><img src="'.e($url).'" alt="'.e($alt).'" onerror="this.style.display=&quot;none&quot;"><div class="media-picker-info"><div class="media-picker-title">'.e($title).'</div><div class="text-[11px] text-slate-400 mt-1 truncate">'.e(basename($m->m_file ?? '')).'</div><div class="media-picker-actions"><button type="button" class="media-picker-insert" data-media-insert data-media-url="'.e($url).'" data-media-rel="'.e($m->m_file ?? '').'" data-media-alt="'.e($alt).'">Tempel</button><button type="button" class="media-picker-copy" data-copy-text="'.e($url).'">Copy</button></div></div></div>';
        }
        echo '</div>';
    }
    echo '</div></div></div>';
    $shown=['b_title_id','b_slug_id','b_excerpt_id','b_content_id','b_focus_keyword_id','b_meta_title_id','b_meta_description_id','b_status','b_is_active','b_is_featured','b_publish_at','b_category_id','b_image'];
    echo '<div style="display:none">';
    foreach($cols as $c){ if($c->Field===$pk || in_array($c->Field,$shown,true) || admin_is_translation_en_field($c->Field,$pairs)) continue; admin_render_field($t,$c,$pk,$edit,$pairs,false); }
    echo '</div>';
}

function admin_ident($name){ return '`'.str_replace('`','``',$name).'`'; }
function admin_regen_raw_all($sql,$params=[]){
    $pdo=db(); if(!$pdo) return [];
    try{ $st=$pdo->prepare($sql); $st->execute($params); return $st->fetchAll(); }catch(Exception $e){ return []; }
}
function admin_regenerate_build_tasks(){
    $tasks=[]; $tables = admin_regen_raw_all("SHOW TABLES");
    foreach($tables as $tr){
        $t = array_values((array)$tr)[0] ?? null;
        if(!$t) continue;
        $cols = admin_regen_raw_all("SHOW COLUMNS FROM ".admin_ident($t));
        $names = array_map(fn($c)=>$c->Field, $cols);
        $pk = $cols[0]->Field ?? null;
        if(!$pk) continue;
        $pairs=[];
        foreach($names as $name){
            if(str_ends_with($name,'_id')){
                $en=substr($name,0,-3).'_en';
                if(in_array($en,$names,true)) $pairs[$name]=$en;
            }
        }
        if(!$pairs) continue;
        $select=[admin_ident($pk)];
        foreach($pairs as $idField=>$enField){ $select[]=admin_ident($idField); }
        $records = admin_regen_raw_all("SELECT ".implode(',', $select)." FROM ".admin_ident($t));
        foreach($records as $r){
            foreach($pairs as $idField=>$enField){
                $source = trim((string)($r->$idField ?? ''));
                if($source === '') continue;
                $tasks[] = ['table'=>$t,'pk'=>$pk,'id'=>$r->$pk,'source_field'=>$idField,'target_field'=>$enField];
            }
        }
    }
    return $tasks;
}
function admin_regenerate_start_session(){
    $tasks = admin_regenerate_build_tasks();
    $_SESSION['regen_tasks'] = $tasks;
    $_SESSION['regen_index'] = 0;
    $_SESSION['regen_total'] = count($tasks);
    $_SESSION['regen_updated'] = 0;
    $_SESSION['regen_skipped'] = 0;
    $_SESSION['regen_started_at'] = time();
}
function admin_regenerate_process_step($limit=1){
    $tasks = $_SESSION['regen_tasks'] ?? [];
    $idx = (int)($_SESSION['regen_index'] ?? 0);
    $total = (int)($_SESSION['regen_total'] ?? count($tasks));
    $updated = (int)($_SESSION['regen_updated'] ?? 0);
    $skipped = (int)($_SESSION['regen_skipped'] ?? 0);
    $messages=[]; $lastProvider='-'; $lastError='';
    $pdo=db();
    $limit = max(1, min(3, (int)$limit));
    for($i=0; $i<$limit && $idx<$total; $i++, $idx++){
        $task = $tasks[$idx] ?? null;
        if(!$task || !$pdo){ $skipped++; continue; }
        $t=$task['table']; $pk=$task['pk']; $idField=$task['source_field']; $enField=$task['target_field']; $id=$task['id'];
        $row = admin_regen_raw_all("SELECT ".admin_ident($idField)." AS src FROM ".admin_ident($t)." WHERE ".admin_ident($pk)."=? LIMIT 1", [$id]);
        $source = trim((string)($row[0]->src ?? ''));
        if($source===''){ $skipped++; continue; }
        $translated = pazar_translate_to_en($source, true);
        $lastProvider = $GLOBALS['pazar_translate_last_provider'] ?? pazar_translation_provider();
        $lastError = $GLOBALS['pazar_translate_last_error'] ?? '';
        if(is_string($translated) && trim($translated)!==''){
            try{
                $st=$pdo->prepare("UPDATE ".admin_ident($t)." SET ".admin_ident($enField)."=? WHERE ".admin_ident($pk)."=?");
                $st->execute([$translated,$id]);
                $updated++;
                $messages[] = $t.'.'.$enField.' #'.$id.' → '.$lastProvider;
            }catch(Exception $e){ $skipped++; $messages[] = $t.'.'.$enField.' #'.$id.' gagal update'; }
        }else{
            $skipped++;
            $messages[] = $t.'.'.$enField.' #'.$id.' dilewati'.($lastError?': '.$lastError:'');
        }
    }
    $_SESSION['regen_index']=$idx; $_SESSION['regen_updated']=$updated; $_SESSION['regen_skipped']=$skipped;
    $done = $idx >= $total;
    if($done){ unset($_SESSION['regen_tasks']); }
    return ['done'=>$done,'index'=>$idx,'total'=>$total,'updated'=>$updated,'skipped'=>$skipped,'percent'=>$total?round($idx/$total*100):100,'provider'=>$lastProvider,'error'=>$lastError,'messages'=>$messages];
}
function admin_regenerate_progress_page(){
    admin_regenerate_start_session();
    admin_shell_start('Generate English Bertahap');
    $total=(int)($_SESSION['regen_total'] ?? 0);
    echo '<div class="admin-card p-6 max-w-5xl"><h2 class="text-2xl font-bold mb-2">Generate ulang English</h2>';
    echo '<p class="text-slate-300 mb-5">Proses sekarang dibuat bertahap supaya halaman tidak muter terus. Sistem akan menerjemahkan 1 data per request, menampilkan progress, dan tidak menimpa data dengan fallback lokal jika Gemini sedang gagal.</p>';
    echo '<div class="mb-4 text-sm text-slate-400">Total task translate: <b class="text-white" id="regenTotal">'.e($total).'</b></div>';
    echo '<div class="w-full bg-slate-900 rounded-full overflow-hidden border border-slate-700 h-5 mb-3"><div id="regenBar" class="h-full bg-emerald-500" style="width:0%"></div></div>';
    echo '<div id="regenStatus" class="mb-4 text-cyan-100">Menyiapkan proses...</div>';
    echo '<pre id="regenLog" class="bg-slate-950 border border-slate-700 rounded-xl p-4 h-72 overflow:auto text-xs whitespace-pre-wrap"></pre>';
    echo '<div class="mt-5 flex flex-wrap gap-2"><a class="btn btn-muted" href="'.admin_base('dashboard').'">Kembali ke Dashboard</a><a class="btn btn-primary" href="'.admin_base('manage?action=regenerate_english_async').'">Ulangi Generate</a></div></div>';
    echo '<script>
    const stepUrl = '.json_encode(admin_base('manage?action=regenerate_english_step')).';
    const bar = document.getElementById("regenBar");
    const statusEl = document.getElementById("regenStatus");
    const logEl = document.getElementById("regenLog");
    function appendLog(lines){ if(!lines) return; lines.forEach(function(x){ logEl.textContent += x + "\\n"; }); logEl.scrollTop = logEl.scrollHeight; }
    async function runStep(){
        try{
            const res = await fetch(stepUrl, {cache:"no-store", credentials:"same-origin"});
            const data = await res.json();
            bar.style.width = (data.percent || 0) + "%";
            statusEl.innerHTML = "Progress: <b>"+(data.index||0)+"/"+(data.total||0)+"</b> ("+(data.percent||0)+"%) — Updated: <b>"+(data.updated||0)+"</b>, Dilewati: <b>"+(data.skipped||0)+"</b>, Provider terakhir: <b>"+(data.provider||"-")+"</b>";
            appendLog(data.messages || []);
            if(data.error){ appendLog(["Catatan: "+data.error]); }
            if(data.done){ statusEl.innerHTML += "<br><span class=\"text-emerald-300 font-bold\">Selesai. Silakan cek halaman /en.</span>"; return; }
            setTimeout(runStep, 450);
        }catch(e){
            statusEl.innerHTML = "<span class=\"text-red-300\">Proses terhenti: "+e+"</span>";
        }
    }
    runStep();
    </script>';
    admin_shell_end();
}
function admin_regenerate_all_english(){
    // Fallback sinkron lama tidak dipakai lagi untuk tombol dashboard, supaya browser tidak muter terlalu lama.
    admin_regenerate_start_session();
    while(($_SESSION['regen_index'] ?? 0) < ($_SESSION['regen_total'] ?? 0)){ admin_regenerate_process_step(1); }
}

function admin_create_database_backup(){
    $pdo=db(); if(!$pdo){ echo 'Database tidak terkoneksi'; exit; }
    $dir=ROOTPATH.'writable'.DIRECTORY_SEPARATOR.'backups'; if(!is_dir($dir)) @mkdir($dir,0775,true);
    $file=$dir.DIRECTORY_SEPARATOR.'backup-'.date('Ymd-His').'.sql';
    $tables=admin_regen_raw_all('SHOW TABLES'); $out="-- Pazar DB Backup\n-- Generated: ".date('c')."\n\nSET FOREIGN_KEY_CHECKS=0;\n";
    foreach($tables as $tr){ $t=array_values((array)$tr)[0] ?? ''; if(!$t) continue; $create=admin_regen_raw_all('SHOW CREATE TABLE '.admin_ident($t)); $createSql=$create[0]->{'Create Table'} ?? ''; $out.="\nDROP TABLE IF EXISTS `{$t}`;\n{$createSql};\n"; $rows=admin_regen_raw_all('SELECT * FROM '.admin_ident($t)); foreach($rows as $r){ $arr=(array)$r; $cols=array_map(fn($x)=>'`'.str_replace('`','``',$x).'`', array_keys($arr)); $vals=array_map(fn($v)=>$v===null?'NULL':$pdo->quote((string)$v), array_values($arr)); $out.='INSERT INTO `'.$t.'` ('.implode(',',$cols).') VALUES ('.implode(',',$vals).');' . "\n"; } }
    $out.="\nSET FOREIGN_KEY_CHECKS=1;\n"; file_put_contents($file,$out); admin_log_activity('backup_database','','',basename($file));
    header('Content-Type: application/sql'); header('Content-Disposition: attachment; filename="'.basename($file).'"'); readfile($file); exit;
}
function pazar_sitemap_entries(){
    $today = date('Y-m-d');
    $entries = [
        ['loc'=>base_url('id'), 'changefreq'=>'weekly', 'priority'=>'1.0', 'lastmod'=>$today],
        ['loc'=>base_url('en'), 'changefreq'=>'weekly', 'priority'=>'1.0', 'lastmod'=>$today],
        ['loc'=>base_url('id/perusahaan-kami'), 'changefreq'=>'monthly', 'priority'=>'0.8', 'lastmod'=>$today],
        ['loc'=>base_url('en/our-company'), 'changefreq'=>'monthly', 'priority'=>'0.8', 'lastmod'=>$today],
        ['loc'=>base_url('id/brand-kami'), 'changefreq'=>'monthly', 'priority'=>'0.8', 'lastmod'=>$today],
        ['loc'=>base_url('en/our-brand'), 'changefreq'=>'monthly', 'priority'=>'0.8', 'lastmod'=>$today],
        ['loc'=>base_url('id/produk'), 'changefreq'=>'weekly', 'priority'=>'0.9', 'lastmod'=>$today],
        ['loc'=>base_url('en/products'), 'changefreq'=>'weekly', 'priority'=>'0.9', 'lastmod'=>$today],
        ['loc'=>base_url('id/resep'), 'changefreq'=>'weekly', 'priority'=>'0.8', 'lastmod'=>$today],
        ['loc'=>base_url('en/recipes'), 'changefreq'=>'weekly', 'priority'=>'0.8', 'lastmod'=>$today],
        ['loc'=>base_url('id/blog'), 'changefreq'=>'weekly', 'priority'=>'0.8', 'lastmod'=>$today],
        ['loc'=>base_url('en/blog'), 'changefreq'=>'weekly', 'priority'=>'0.8', 'lastmod'=>$today],
        ['loc'=>base_url('id/info-karir'), 'changefreq'=>'monthly', 'priority'=>'0.6', 'lastmod'=>$today],
        ['loc'=>base_url('en/career-info'), 'changefreq'=>'monthly', 'priority'=>'0.6', 'lastmod'=>$today],
        ['loc'=>base_url('id/lowongan'), 'changefreq'=>'weekly', 'priority'=>'0.7', 'lastmod'=>$today],
        ['loc'=>base_url('en/vacancies'), 'changefreq'=>'weekly', 'priority'=>'0.7', 'lastmod'=>$today],
    ];
    foreach(rows("SELECT p_title_id,p_title_en,COALESCE(p_updated_at,p_created_at,NOW()) AS lastmod FROM pazar_product WHERE p_is_active=1") as $p){
        $lm = !empty($p->lastmod) ? date('Y-m-d', strtotime($p->lastmod)) : $today;
        $entries[]=['loc'=>base_url('id/produk/'.slugify($p->p_title_id??'')), 'changefreq'=>'weekly', 'priority'=>'0.8', 'lastmod'=>$lm];
        $entries[]=['loc'=>base_url('en/product/'.slugify(($p->p_title_en??'') ?: ($p->p_title_id??''))), 'changefreq'=>'weekly', 'priority'=>'0.8', 'lastmod'=>$lm];
    }
    foreach(rows("SELECT r_title_id,r_title_en,COALESCE(r_updated_at,r_created_at,NOW()) AS lastmod FROM pazar_recipe WHERE r_is_active=1") as $r){
        $lm = !empty($r->lastmod) ? date('Y-m-d', strtotime($r->lastmod)) : $today;
        $entries[]=['loc'=>base_url('id/resep/'.slugify($r->r_title_id??'')), 'changefreq'=>'weekly', 'priority'=>'0.7', 'lastmod'=>$lm];
        $entries[]=['loc'=>base_url('en/recipe/'.slugify(($r->r_title_en??'') ?: ($r->r_title_id??''))), 'changefreq'=>'weekly', 'priority'=>'0.7', 'lastmod'=>$lm];
    }
    foreach(rows("SELECT b_title_id,b_title_en,b_slug_id,b_slug_en,COALESCE(b_updated_at,b_publish_at,b_created_at,NOW()) AS lastmod FROM pazar_blog WHERE b_is_active=1 AND b_status='published'") as $b){
        $lm = !empty($b->lastmod) ? date('Y-m-d', strtotime($b->lastmod)) : $today;
        $entries[]=['loc'=>base_url('id/blog/'.(($b->b_slug_id??'') ?: slugify($b->b_title_id??''))), 'changefreq'=>'weekly', 'priority'=>'0.75', 'lastmod'=>$lm];
        $entries[]=['loc'=>base_url('en/blog/'.(($b->b_slug_en??'') ?: slugify(($b->b_title_en??'') ?: ($b->b_title_id??'')))), 'changefreq'=>'weekly', 'priority'=>'0.75', 'lastmod'=>$lm];
    }
    $seen=[]; $clean=[];
    foreach($entries as $entry){
        $loc = $entry['loc'] ?? ''; if($loc==='' || isset($seen[$loc])) continue; $seen[$loc]=true; $clean[]=$entry;
    }
    return $clean;
}
function admin_generate_sitemap(){
    $xml='<?xml version="1.0" encoding="UTF-8"?>' . "\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n";
    foreach(pazar_sitemap_entries() as $entry){
        $xml .= "  <url>\n";
        $xml .= "    <loc>".e($entry['loc'])."</loc>\n";
        if(!empty($entry['lastmod'])) $xml .= "    <lastmod>".e($entry['lastmod'])."</lastmod>\n";
        $xml .= "    <changefreq>".e($entry['changefreq'] ?? 'weekly')."</changefreq>\n";
        $xml .= "    <priority>".e($entry['priority'] ?? '0.8')."</priority>\n";
        $xml .= "  </url>\n";
    }
    $xml.="</urlset>\n";
    $file=PUBLICPATH.'sitemap.xml'; file_put_contents($file,$xml); admin_log_activity('generate_sitemap','','','sitemap.xml'); return $file;
}
function admin_generate_robots(){
    $robots = "User-agent: *\n";
    $robots .= "Allow: /\n";
    $robots .= "Disallow: /panel-pazar-seasonings/\n";
    $robots .= "Disallow: /writable/\n";
    $robots .= "Disallow: /vendor/\n";
    $robots .= "Disallow: /app/\n";
    $robots .= "Disallow: /legacy/\n";
    $robots .= "\nSitemap: ".base_url('sitemap.xml')."\n";
    $file=PUBLICPATH.'robots.txt'; file_put_contents($file,$robots); admin_log_activity('generate_robots','','','robots.txt'); return $file;
}

function admin_auto_refresh_seo_files($table='') {
    // Regenerate SEO files automatically after public content changes, so sitemap stays current.
    $watched = ['pazar_blog','pazar_product','pazar_recipe','pazar_vacancy'];
    if ($table !== '' && !in_array($table, $watched, true)) {
        return;
    }
    try {
        pazar_clear_frontend_cache();
        admin_generate_sitemap();
        if (!is_file(PUBLICPATH.'robots.txt')) {
            admin_generate_robots();
        }
    } catch (Throwable $e) {
        admin_log_activity('auto_refresh_seo_failed', $table, '', $e->getMessage());
    }
}
function admin_manage(){
    $user=$_SESSION['admin'];
    $allowed=admin_allowed_tables($user);
    if(($_GET['action'] ?? '') === 'regenerate_english' || ($_GET['action'] ?? '') === 'regenerate_english_async'){
        @set_time_limit(30);
        admin_regenerate_progress_page(); exit;
    }
    if(($_GET['action'] ?? '') === 'regenerate_english_step'){
        @set_time_limit(60);
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode(admin_regenerate_process_step(1), JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); exit;
    }
    if(($_GET['action'] ?? '') === 'test_gemini'){
        $sample = 'Tanpa perlu menakar dan meracik, makanan lezat siap lebih cepat';
        $result = pazar_gemini_translate_to_en($sample);
        admin_shell_start('Test Gemini Translate');
        echo '<div class="admin-card p-5"><h2 class="text-xl font-semibold mb-4">Test Gemini Translate</h2>';
        echo '<p class="text-sm text-slate-400 mb-2">Model yang dicoba:</p><div class="p-3 rounded bg-slate-900 mb-4">'.e(implode(', ', pazar_gemini_candidate_models())).'</div>';
        echo '<p class="text-sm text-slate-400 mb-2">Kalimat test:</p><div class="p-3 rounded bg-slate-900 mb-4">'.e($sample).'</div>';
        if($result){ echo '<p class="text-sm text-slate-400 mb-2">Hasil Gemini:</p><div class="p-3 rounded bg-emerald-950 border border-emerald-700 mb-4">'.e($result).'</div>'; }
        else { echo '<div class="p-3 rounded bg-red-950 border border-red-700 mb-4">Gemini gagal dipanggil: '.e($GLOBALS['pazar_translate_last_error'] ?? 'Tidak diketahui').'</div>'; }
        echo '<a class="btn btn-muted" href="'.admin_base('dashboard').'">Kembali ke Dashboard</a></div>';
        admin_shell_end();
    }
    if(($_GET['action'] ?? '') === 'backup_database'){
        admin_create_database_backup();
    }
    if(($_GET['action'] ?? '') === 'generate_sitemap'){
        $file = admin_generate_sitemap();
        $_SESSION['translate_flash'] = $file ? 'Sitemap berhasil dibuat: '.basename($file) : 'Sitemap gagal dibuat.';
        header('Location: '.admin_base('dashboard')); exit;
    }
    if(($_GET['action'] ?? '') === 'generate_robots'){
        $file = admin_generate_robots();
        $_SESSION['translate_flash'] = $file ? 'Robots.txt berhasil dibuat: '.basename($file) : 'Robots.txt gagal dibuat.';
        header('Location: '.admin_base('dashboard')); exit;
    }
    if(($_GET['action'] ?? '') === 'translate_one'){
        $t=$_GET['table'] ?? ''; $id=$_GET['id'] ?? '';
        if(!isset($allowed[$t])){ header('Location: '.admin_base('dashboard')); exit; }
        $cols=rows("SHOW COLUMNS FROM ".admin_ident($t)); $pairs=admin_translation_pairs($cols); $pk=$cols[0]->Field ?? '';
        $edit=$pk ? row("SELECT * FROM ".admin_ident($t)." WHERE ".admin_ident($pk)."=?",[$id]) : null;
        $updated=0; $err='';
        if($edit && $pairs){ $data=[]; foreach($pairs as $idField=>$enField){ $src=trim((string)($edit->$idField ?? '')); if($src==='') continue; $tr=pazar_translate_to_en($src,true); if(is_string($tr) && trim($tr)!==''){ $data[$enField]=$tr; $updated++; } else { $err=$GLOBALS['pazar_translate_last_error'] ?? ''; } } if($data){ $set=implode(',',array_map(fn($k)=>admin_ident($k).'=?',array_keys($data))); rows("UPDATE ".admin_ident($t)." SET $set WHERE ".admin_ident($pk)."=?", array_merge(array_values($data),[$id])); admin_log_activity('translate_one',$t,$id,($GLOBALS['pazar_translate_last_provider'] ?? '')); } }
        $_SESSION['translate_flash'] = $updated ? 'English data #'.$id.' berhasil diperbarui. Provider: '.($GLOBALS['pazar_translate_last_provider'] ?? pazar_translation_provider()) : 'English gagal diperbarui'.($err?': '.$err:'');
        header('Location: '.admin_base('manage?table='.$t.'&edit='.$id)); exit;
    }
    $t=$_GET['table']??array_key_first($allowed);
    if(!isset($allowed[$t])){ $t=array_key_first($allowed); }
    if(!$t){ admin_dashboard(); }
    $cols=rows("SHOW COLUMNS FROM `$t`");
    if(!$cols){ admin_shell_start('Data tidak ditemukan'); echo '<div class="admin-card p-5 bg-red-900/50">Tabel tidak ditemukan.</div>'; admin_shell_end(); }
    $pairs=admin_translation_pairs($cols);
    $pk=$cols[0]->Field;
    if($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['save_table'])){
        $data=[];
        foreach($cols as $c){
            $field=$c->Field;
            if($field===$pk) continue;
            if(admin_is_audit_field($field)) continue;
            if(admin_is_file_field($field)){
                if($t==='pazar_blog' && $field==='b_image' && array_key_exists($field,$_POST)){
                    $data[$field]=trim((string)$_POST[$field]);
                    continue;
                }
                $uploaded = admin_save_uploaded_file($t,$field);
                if($uploaded !== null) $data[$field]=$uploaded;
                elseif(isset($_POST['existing_'.$field])) $data[$field]=$_POST['existing_'.$field];
                continue;
            }
            if(isset($_POST[$field])) $data[$field]=$_POST[$field];
        }
        $autoTranslate = ($_POST['auto_translate_en'] ?? '1') === '1';
        foreach($pairs as $idField=>$enField){
            $source = trim((string)($data[$idField] ?? ''));
            if($source !== ''){
                $manual = trim((string)($data[$enField] ?? ''));
                if($autoTranslate || $manual === ''){
                    $autoResult = pazar_translate_to_en($source);
                    if(is_string($autoResult) && trim($autoResult) !== ''){
                        $data[$enField] = $autoResult;
                    } elseif($manual !== ''){
                        $data[$enField] = $manual;
                    } elseif($edit && isset($edit->$enField) && trim((string)$edit->$enField) !== ''){
                        $data[$enField] = $edit->$enField; // Jangan timpa English lama dengan hasil fallback jelek saat Gemini sedang 503.
                    } else {
                        $data[$enField] = $source; // fallback terakhir agar halaman tidak kosong.
                    }
                }
            }
        }
        if($autoTranslate && $pairs){
            $_SESSION['translate_flash'] = 'Auto English diproses. Provider terakhir: '.($GLOBALS['pazar_translate_last_provider'] ?? pazar_translation_provider()).(($GLOBALS['pazar_translate_last_error'] ?? '') ? '. Jika hasil masih kurang natural, cek catatan error: '.($GLOBALS['pazar_translate_last_error'] ?? '') : '');
        }
        $now=date('Y-m-d H:i:s');
        if($edit){ admin_save_revision($t, $pk, $edit->$pk ?? '', 'before_update', $edit); }
        $colNames=array_map(fn($c)=>$c->Field,$cols);
        foreach($colNames as $cn){ if(preg_match('~(^|_)updated_at$~',$cn)) $data[$cn]=$now; }
        if(!empty($_POST[$pk])){
            $set=implode(',',array_map(fn($k)=>"`$k`=?",array_keys($data)));
            if($set){ rows("UPDATE `$t` SET $set WHERE `$pk`=?",array_merge(array_values($data),[$_POST[$pk]])); admin_log_activity('update',$t,$_POST[$pk]); }
        }else{
            foreach($colNames as $cn){ if(preg_match('~(^|_)created_at$~',$cn) && !isset($data[$cn])) $data[$cn]=$now; }
            foreach($colNames as $cn){ if(preg_match('~(^|_)created_by$~',$cn) && !isset($data[$cn])) $data[$cn]='CMS'; }
            $keys=array_keys($data);
            if($keys){ rows("INSERT INTO `$t` (`".implode('`,`',$keys)."`) VALUES (".implode(',',array_fill(0,count($keys),'?')).")",array_values($data)); admin_log_activity('create',$t,db()?db()->lastInsertId():''); }
        }
        admin_auto_refresh_seo_files($t);
        header('Location: '.admin_base('manage?table='.$t)); exit;
    }
    if(isset($_GET['delete'])){
        $deleteId=$_GET['delete'];
        if(!admin_can_delete_table($t)){
            $_SESSION['translate_flash']='Akun ini tidak diizinkan menghapus data. Gunakan Nonaktif/Arsip jika perlu.';
            header('Location: '.admin_base('manage?table='.$t)); exit;
        }
        $activeField=admin_active_field($cols);
        if($activeField){ rows("UPDATE ".admin_ident($t)." SET ".admin_ident($activeField)."=0 WHERE ".admin_ident($pk)."=?",[$deleteId]); admin_log_activity('archive',$t,$deleteId,'soft delete by inactive field'); }
        else { rows("DELETE FROM ".admin_ident($t)." WHERE ".admin_ident($pk)."=?",[$deleteId]); admin_log_activity('delete',$t,$deleteId,'permanent'); }
        admin_auto_refresh_seo_files($t);
        header('Location: '.admin_base('manage?table='.$t)); exit;
    }
    $edit=isset($_GET['edit'])?row("SELECT * FROM `$t` WHERE `$pk`=?",[$_GET['edit']]):null;
    $items=rows("SELECT * FROM `$t` ORDER BY `$pk` DESC LIMIT 100");
    admin_shell_start($allowed[$t], $t);
    if(!empty($_SESSION['translate_flash'])){ echo '<div class="mb-5 p-4 rounded-xl border border-sky-700 bg-sky-950/40 text-sky-100">'.e($_SESSION['translate_flash']).'</div>'; unset($_SESSION['translate_flash']); }
    echo '<div class="admin-card p-5 mb-8"><div class="flex flex-wrap items-center justify-between gap-3 mb-5"><div><h2 class="font-semibold text-lg">'.($edit?'Edit Data':'Tambah Data').'</h2><p class="text-sm text-slate-400 mt-1">Panel dibuat satu bahasa utama: isi Bahasa Indonesia saja. Saat disimpan, sistem otomatis membuat versi English memakai Gemini API, dengan pengaman agar hasil lama tidak rusak saat Gemini overload. Link /id dan /en tetap aktif di frontend.</p></div><div class="flex flex-wrap gap-2"><a class="btn btn-muted" href="'.admin_base('manage?table='.$t).'">Reset Form</a>'.($edit && $pairs ? '<a class="btn btn-muted" href="'.admin_base('manage?action=translate_one&table='.$t.'&id='.$edit->$pk).'">Generate English Data Ini</a>' : '').'</div></div>';
    if($edit){ $previewNow=admin_preview_urls($t,$edit,$cols); if($previewNow){ echo '<div class="mb-5 flex flex-wrap gap-2"><span class="text-sm text-slate-400 py-2">Preview sebelum publish:</span>'; foreach($previewNow as $lbl=>$url){ echo '<a target="_blank" class="btn btn-muted" href="'.e($url).'">Preview '.e($lbl).'</a>'; } echo '</div>'; } }
    if($pairs){ [$st,$tx]= $edit ? admin_translation_status($edit,$pairs) : ['none','Data baru']; echo '<div class="mb-5">'.admin_badge($st,$tx).'</div>'; }
    if($pairs){
        echo '<div class="mb-5 p-4 rounded-xl border border-emerald-700 bg-emerald-950/30"><label class="flex items-start gap-3 cursor-pointer"><input type="checkbox" name="auto_translate_en" value="1" checked form="adminDataForm" class="mt-1"><span><b>Auto English saat simpan</b><br><span class="text-sm text-emerald-100/80">Kolom English dibuat otomatis dari Bahasa Indonesia. Provider default: Gemini API. Jika Gemini sedang 503/limit, sistem tidak akan menimpa English lama dengan hasil kamus lokal yang jelek. Hasil bisa dikoreksi manual lewat bagian Advanced English.</span></span></label></div>';
    }
    echo '<form id="adminDataForm" method="post" enctype="multipart/form-data"><input type="hidden" name="save_table" value="1"><input type="hidden" name="'.$pk.'" value="'.e($edit->$pk??'').'">';
    if($t==='pazar_blog'){
        admin_render_blog_writer_form($t,$cols,$pk,$edit,$pairs);
    }else{
        echo '<div class="admin-form-grid">';
        foreach($cols as $c){
            if(admin_is_translation_en_field($c->Field,$pairs)) continue;
            admin_render_field($t,$c,$pk,$edit,$pairs,false);
        }
        echo '</div>';
    }
    if($pairs){
        echo '<details class="mt-6 rounded-xl border border-slate-700 bg-slate-900/40"><summary class="cursor-pointer px-4 py-3 font-semibold text-sky-200">Advanced English / Koreksi Manual</summary><div class="p-4 border-t border-slate-700"><p class="text-sm text-slate-400 mb-4">Bagian ini tidak wajib diisi. Jika Auto English tetap aktif, nilai English akan diperbarui otomatis setiap klik Simpan. Hilangkan centang Auto English jika ingin mempertahankan hasil koreksi manual.</p><div class="admin-form-grid">';
        foreach($cols as $c){ if(admin_is_translation_en_field($c->Field,$pairs)) admin_render_field($t,$c,$pk,$edit,$pairs,true); }
        echo '</div></div></details>';
    }
    echo '<div class="admin-actions-sticky"><button class="btn btn-primary" type="submit"><i data-lucide="save" class="w-4 h-4"></i>Simpan Data + Auto English</button></div></form></div><div class="admin-card admin-table-wrap admin-scroll"><table class="admin-table"><thead><tr>';
    $tableCols=array_values(array_filter(admin_visible_table_cols($cols,$pairs), fn($c)=>$c->Field!==$pk));
    foreach($tableCols as $c){ echo '<th>'.e(isset($pairs[$c->Field]) ? admin_translation_base_label($c->Field) : admin_field_label($c->Field)).'</th>'; }
    echo '<th>English</th><th>SEO</th><th>Preview</th><th>Aksi</th></tr></thead><tbody>';
    foreach($items as $it){
        echo '<tr>'; foreach($tableCols as $c){ $v=$it->{$c->Field}??''; echo '<td>'.admin_short_value($c->Field,$v,$t).'</td>'; }
        [$trStatus,$trText]=admin_translation_status($it,$pairs); [$seoStatus,$seoText]=admin_seo_status($it,$cols);
        echo '<td>'.admin_badge($trStatus,$trText).'</td><td>'.admin_badge($seoStatus,$seoText).'</td><td class="whitespace-nowrap">';
        $preview=admin_preview_urls($t,$it,$cols); if($preview){ foreach($preview as $lbl=>$url){ echo '<a target="_blank" class="text-sky-300 hover:underline mr-2" href="'.e($url).'">'.e($lbl).'</a>'; } } else echo '<span class="text-slate-500">-</span>'; echo '</td>';
        echo '<td class="whitespace-nowrap"><a class="text-sky-400 hover:underline" href="'.admin_base('manage?table='.$t.'&edit='.$it->$pk).'">Edit</a> <span class="text-slate-600">|</span> ';
        if($pairs) echo '<a class="text-emerald-300 hover:underline" href="'.admin_base('manage?action=translate_one&table='.$t.'&id='.$it->$pk).'">Translate</a> <span class="text-slate-600">|</span> ';
        echo '<a class="btn-danger hover:underline" onclick="return confirm(\'Nonaktifkan/arsipkan data ini?\')" href="'.admin_base('manage?table='.$t.'&delete='.$it->$pk).'">'.(admin_active_field($cols)?'Arsip':'Hapus').'</a></td></tr>';
    }
    echo '</tbody></table></div>';
    admin_shell_end();
}

function admin_manage_users(){
    if(!admin_is_super_admin()){ header('Location: '.admin_base('dashboard')); exit; }
    pazar_bootstrap_v16();
    $flash='';
    if($_SERVER['REQUEST_METHOD']==='POST'){
        $id=(int)($_POST['u_id'] ?? 0);
        $name=trim($_POST['u_name'] ?? '');
        $email=strtolower(trim($_POST['u_email'] ?? ''));
        $role=trim($_POST['u_role'] ?? 'admin');
        $active=isset($_POST['u_is_active']) ? 1 : 0;
        $pass=trim($_POST['u_password'] ?? '');
        if($name!=='' && filter_var($email,FILTER_VALIDATE_EMAIL)){
            if($id>0){
                $sets=['u_name=?','u_email=?','u_role=?','u_is_active=?','u_updated_at=NOW()']; $params=[$name,$email,$role,$active];
                if($pass!==''){ $sets[]='u_password=?'; $params[]=password_hash($pass,PASSWORD_DEFAULT); }
                $params[]=$id;
                rows('UPDATE login_users SET '.implode(',',$sets).' WHERE u_id=?',$params);
                admin_log_activity('update','login_users',$id,'manage user');
                $flash='User berhasil diperbarui.';
            }else{
                if($pass==='') $pass='admin123';
                $cols=array_map(fn($c)=>$c->Field, rows('SHOW COLUMNS FROM login_users'));
                $data=['u_name'=>$name,'u_email'=>$email,'u_password'=>password_hash($pass,PASSWORD_DEFAULT),'u_role'=>$role,'u_is_active'=>$active];
                if(in_array('u_employee_id',$cols,true)) $data['u_employee_id']='ADM'.date('His');
                if(in_array('u_join_date',$cols,true)) $data['u_join_date']=date('Y-m-d');
                if(in_array('u_created_by',$cols,true)) $data['u_created_by']='CMS';
                if(in_array('u_created_at',$cols,true)) $data['u_created_at']=date('Y-m-d H:i:s');
                $keys=array_values(array_filter(array_keys($data), fn($k)=>in_array($k,$cols,true)));
                rows('INSERT INTO login_users (`'.implode('`,`',$keys).'`) VALUES ('.implode(',',array_fill(0,count($keys),'?')).')', array_map(fn($k)=>$data[$k], $keys));
                admin_log_activity('create','login_users',db()?db()->lastInsertId():'','manage user');
                $flash='User berhasil dibuat. Password default dipakai jika kolom password dikosongkan.';
            }
        }else{ $flash='Nama dan email valid wajib diisi.'; }
        $_SESSION['translate_flash']=$flash;
        header('Location: '.admin_base('users')); exit;
    }
    if(isset($_GET['toggle'])){
        $id=(int)$_GET['toggle']; rows('UPDATE login_users SET u_is_active=IF(u_is_active=1,0,1), u_updated_at=NOW() WHERE u_id=?',[$id]);
        admin_log_activity('toggle','login_users',$id,'active status'); header('Location: '.admin_base('users')); exit;
    }
    $edit=isset($_GET['edit'])?row('SELECT * FROM login_users WHERE u_id=?',[(int)$_GET['edit']]):null;
    $users=rows('SELECT u_id,u_name,u_email,u_role,u_is_active,u_created_at,u_updated_at FROM login_users ORDER BY u_id DESC LIMIT 200');
    admin_shell_start('Manage User');
    if(!empty($_SESSION['translate_flash'])){ echo '<div class="mb-5 p-4 rounded-xl border border-emerald-700 bg-emerald-950/40 text-emerald-100">'.e($_SESSION['translate_flash']).'</div>'; unset($_SESSION['translate_flash']); }
    echo '<div class="grid lg:grid-cols-[420px_1fr] gap-6"><div class="admin-card p-5"><h2 class="text-xl font-black mb-2">'.($edit?'Edit User':'Tambah User').'</h2><p class="text-sm text-slate-400 mb-5">Kelola akun admin website. Hanya super admin yang bisa membuka menu ini.</p><form method="post" class="space-y-4"><input type="hidden" name="u_id" value="'.e($edit->u_id ?? '').'"><div><label class="admin-label">Nama</label><input class="admin-input" name="u_name" value="'.e($edit->u_name ?? '').'" required></div><div><label class="admin-label">Email Login</label><input type="email" class="admin-input" name="u_email" value="'.e($edit->u_email ?? '').'" required></div><div><label class="admin-label">Role</label><select class="admin-select" name="u_role"><option value="super_admin" '.(((string)($edit->u_role??'')==='super_admin')?'selected':'').'>Super Admin</option><option value="admin" '.(((string)($edit->u_role??'admin')==='admin')?'selected':'').'>Admin CMS</option><option value="sosmed" '.(((string)($edit->u_role??'')==='sosmed')?'selected':'').'>Sosmed / Content</option></select></div><div><label class="admin-label">Password '.($edit?'Baru':'').'</label><input type="password" class="admin-input" name="u_password" placeholder="'.($edit?'Kosongkan jika tidak diganti':'Kosongkan = admin123').'" autocomplete="new-password"></div><label class="flex items-center gap-3"><input type="checkbox" name="u_is_active" value="1" '.(((int)($edit->u_is_active ?? 1)===1)?'checked':'').'><span>Aktif</span></label><div class="flex gap-2"><button class="btn btn-primary" type="submit"><i data-lucide="save" class="w-4 h-4"></i>Simpan User</button><a class="btn btn-muted" href="'.admin_base('users').'">Reset</a></div></form></div><div class="admin-card admin-table-wrap"><table class="admin-table"><thead><tr><th>Nama</th><th>Email</th><th>Role</th><th>Status</th><th>Aksi</th></tr></thead><tbody>';
    foreach($users as $u){ echo '<tr><td>'.e($u->u_name).'</td><td>'.e($u->u_email).'</td><td><span class="badge">'.e($u->u_role ?: 'admin').'</span></td><td>'.(((int)$u->u_is_active===1)?admin_badge('ok','Aktif'):admin_badge('empty','Nonaktif')).'</td><td class="whitespace-nowrap"><a class="text-sky-300 hover:underline" href="'.admin_base('users?edit='.$u->u_id).'">Edit</a> <span class="text-slate-600">|</span> <a class="text-amber-300 hover:underline" onclick="return confirm(\'Ubah status user ini?\')" href="'.admin_base('users?toggle='.$u->u_id).'">Aktif/Nonaktif</a></td></tr>'; }
    echo '</tbody></table></div></div>';
    admin_shell_end();
}
function admin_cms_tools(){
    admin_shell_start('CMS Tools');
    $cards=[
        ['Media Library','Pusat data gambar/file. Dipakai untuk mencatat asset, alt text, caption, dan kebutuhan halaman.','pazar_media_library','image'],
        ['Menu Frontend','Siapkan struktur menu depan jika ingin menu dibuat dinamis dari database.','pazar_frontend_menu','menu'],
        ['Page Builder Blocks','Blok konten fleksibel untuk landing page atau section tambahan.','pazar_page_blocks','layout-dashboard'],
        ['SEO Global','Pengaturan meta global, keyword, dan deskripsi umum website.','pazar_seo_global','newspaper'],
        ['Notifikasi Admin','Catatan/pengingat internal untuk admin website.','pazar_admin_notifications','badge-check'],
        ['Riwayat Revisi','Melihat jejak perubahan konten sebelum update. Berguna untuk audit dan rollback manual.','pazar_content_revisions','settings-2'],
    ];
    echo '<div class="admin-card p-6 mb-6"><h2 class="text-2xl font-black mb-2">CMS Tools</h2><p class="text-slate-300 leading-relaxed">Menu ini adalah perlengkapan pendukung CMS, bukan halaman frontend langsung. Gunanya untuk merapikan asset, SEO, blok halaman, menu, notifikasi, dan riwayat revisi supaya pengelolaan website lebih matang.</p></div><div class="tool-grid">';
    foreach($cards as $c){ echo '<div class="tool-card"><div class="flex items-center gap-3 mb-3"><i data-lucide="'.e($c[3]).'" class="w-6 h-6 text-emerald-300"></i><h3>'.e($c[0]).'</h3></div><p>'.e($c[1]).'</p><a class="btn btn-success" href="'.admin_base('manage?table='.$c[2]).'">Kelola</a></div>'; }
    echo '</div>';
    admin_shell_end();
}
function admin_save_media_library_upload($file,$title='',$alt='',$caption=''){
    if(($file['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) return [false,'File gagal diupload.'];
    $name = $file['name'] ?? 'media-file';
    $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
    $allowed = ['jpg','jpeg','png','webp','gif','svg','pdf'];
    if(!in_array($ext,$allowed,true)) return [false,'Format file tidak didukung. Gunakan JPG, PNG, WebP, GIF, SVG, atau PDF.'];
    $folder = 'media-library/'.date('Ym');
    $dir = PUBLICPATH.'storage/'.$folder;
    if(!is_dir($dir)) @mkdir($dir,0775,true);
    $safeBase = slugify(pathinfo($name,PATHINFO_FILENAME));
    if($safeBase==='') $safeBase='media';
    $fileName = date('YmdHis').'-'.substr(sha1($name.microtime(true).random_int(1,999999)),0,8).'-'.$safeBase.'.'.$ext;
    $dest = $dir.'/'.$fileName;
    if(!move_uploaded_file($file['tmp_name'],$dest)) return [false,'File tidak bisa disimpan ke folder storage.'];
    $before = is_file($dest) ? filesize($dest) : 0;
    admin_optimize_image_file($dest,$ext,1600,82);
    $after = is_file($dest) ? filesize($dest) : 0;
    $rel = $folder.'/'.$fileName;
    $mime = is_file($dest) ? (mime_content_type($dest) ?: '') : '';
    $w=0; $h=0;
    if(is_file($dest) && pazar_is_image_path($dest) && function_exists('getimagesize')){ $info=@getimagesize($dest); if($info){$w=(int)$info[0]; $h=(int)$info[1];} }
    $finalTitle = trim($title) !== '' ? trim($title) : pathinfo($name,PATHINFO_FILENAME);
    try{
        rows("INSERT INTO pazar_media_library (m_title,m_file,m_alt_id,m_caption_id,m_mime,m_size,m_width,m_height,m_used_for,m_is_active,m_created_at) VALUES (?,?,?,?,?,?,?,?,?,?,NOW())", [$finalTitle,$rel,$alt,$caption,$mime,$after,$w,$h,'media-library',1]);
        admin_log_activity('upload','pazar_media_library',db()?db()->lastInsertId():'',$rel.' compressed '.(int)$before.' -> '.(int)$after);
    }catch(Exception $e){}
    return [true,$rel];
}


function admin_media_library_json(){
    pazar_bootstrap_v16();
    header('Content-Type: application/json; charset=utf-8');
    $q=trim($_GET['q'] ?? '');
    $where='WHERE m_is_active=1'; $params=[];
    if($q!==''){
        $where.=' AND (m_title LIKE ? OR m_file LIKE ? OR m_alt_id LIKE ? OR m_caption_id LIKE ?)';
        $like='%'.$q.'%'; $params=[$like,$like,$like,$like];
    }
    $rows=rows('SELECT * FROM pazar_media_library '.$where.' ORDER BY m_id DESC LIMIT 240',$params);
    $items=[];
    foreach($rows as $m){
        if(!pazar_is_image_path($m->m_file ?? '')) continue;
        $file=(string)($m->m_file ?? '');
        $title=(string)($m->m_title ?: basename($file));
        $items[]=[
            'id'=>(int)($m->m_id ?? 0),
            'title'=>$title,
            'alt'=>(string)($m->m_alt_id ?: $title),
            'file'=>$file,
            'rel'=>$file,
            'basename'=>basename($file),
            'url'=>pazar_file_url($file,'pazar_media_library','m_file'),
            'width'=>(int)($m->m_width ?? 0),
            'height'=>(int)($m->m_height ?? 0),
            'size'=>(int)($m->m_size ?? 0),
        ];
    }
    echo json_encode(['ok'=>true,'items'=>$items], JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);
    exit;
}

function admin_media_library(){
    pazar_bootstrap_v16();
    $flash=[];
    if(isset($_GET['delete'])){
        $id=(int)$_GET['delete'];
        $m=row('SELECT * FROM pazar_media_library WHERE m_id=? LIMIT 1',[$id]);
        if($m){
            $rel=ltrim((string)($m->m_file ?? ''),'/');
            if($rel!=='' && !preg_match('~^https?://~i',$rel)){
                $file=PUBLICPATH.'storage/'.$rel;
                if(is_file($file)) @unlink($file);
            }
            rows('DELETE FROM pazar_media_library WHERE m_id=?',[$id]);
            admin_log_activity('delete','pazar_media_library',$id,'media deleted permanently');
            $_SESSION['translate_flash']='Media berhasil dihapus permanen.';
        } else { $_SESSION['translate_flash']='Media tidak ditemukan.'; }
        header('Location: '.admin_base('media-library')); exit;
    }
    if($_SERVER['REQUEST_METHOD']==='POST'){
        $title=trim($_POST['m_title'] ?? ''); $alt=trim($_POST['m_alt_id'] ?? ''); $caption=trim($_POST['m_caption_id'] ?? '');
        if(!empty($_FILES['media_files']['name']) && is_array($_FILES['media_files']['name'])){
            $count=count($_FILES['media_files']['name']);
            for($i=0;$i<$count;$i++){
                $f=['name'=>$_FILES['media_files']['name'][$i] ?? '', 'type'=>$_FILES['media_files']['type'][$i] ?? '', 'tmp_name'=>$_FILES['media_files']['tmp_name'][$i] ?? '', 'error'=>$_FILES['media_files']['error'][$i] ?? UPLOAD_ERR_NO_FILE, 'size'=>$_FILES['media_files']['size'][$i] ?? 0];
                if(($f['error'] ?? UPLOAD_ERR_NO_FILE)===UPLOAD_ERR_NO_FILE) continue;
                [$ok,$msg]=admin_save_media_library_upload($f,$title,$alt,$caption); $flash[]=$ok ? 'Berhasil upload: '.$msg : $msg;
            }
        }
        $_SESSION['translate_flash']=$flash ? implode(' | ',$flash) : 'Pilih minimal satu file untuk diupload.';
        header('Location: '.admin_base('media-library')); exit;
    }
    $q=trim($_GET['q'] ?? '');
    $where='WHERE m_is_active=1'; $params=[];
    if($q!==''){ $where.=' AND (m_title LIKE ? OR m_file LIKE ? OR m_alt_id LIKE ? OR m_caption_id LIKE ?)'; $like='%'.$q.'%'; $params=[$like,$like,$like,$like]; }
    $media=rows('SELECT * FROM pazar_media_library '.$where.' ORDER BY m_id DESC LIMIT 240',$params);
    $total=(int)(row('SELECT COUNT(*) AS c FROM pazar_media_library WHERE m_is_active=1')->c ?? 0);
    admin_shell_start('Media Library');
    if(!empty($_SESSION['translate_flash'])){ echo '<div class="mb-5 p-4 rounded-xl border border-emerald-700 bg-emerald-950/40 text-emerald-100">'.e($_SESSION['translate_flash']).'</div>'; unset($_SESSION['translate_flash']); }
    echo '<div class="grid lg:grid-cols-[420px_1fr] gap-6">';
    echo '<section class="admin-card p-5"><h2 class="text-2xl font-black mb-2 flex items-center gap-2"><i data-lucide="image" class="w-6 h-6 text-emerald-300"></i>Media Library</h2><p class="text-slate-300 leading-relaxed mb-5">Upload gambar untuk artikel, produk, resep, atau halaman website. Foto JPG/PNG/WebP akan otomatis dikompres dan diperkecil maksimal 1600px supaya website tetap ringan.</p><form method="post" enctype="multipart/form-data" class="space-y-4"><div class="media-upload-box"><label class="admin-label">Upload Foto / File</label><input class="admin-input" type="file" name="media_files[]" multiple accept=".jpg,.jpeg,.png,.webp,.gif,.svg,.pdf"><div class="admin-help">Bisa pilih banyak file sekaligus. Setelah upload, klik tombol Copy Link pada kartu media.</div></div><div><label class="admin-label">Judul Media</label><input class="admin-input" name="m_title" placeholder="Opsional, misal: Foto produk bumbu nasi goreng"></div><div><label class="admin-label">Alt Text Gambar</label><input class="admin-input" name="m_alt_id" placeholder="Deskripsi singkat gambar untuk SEO"></div><div><label class="admin-label">Caption</label><textarea class="admin-textarea" name="m_caption_id" rows="3" placeholder="Opsional"></textarea></div><button class="btn btn-primary" type="submit"><i data-lucide="upload" class="w-4 h-4"></i>Upload & Compress</button></form><div class="grid grid-cols-2 gap-3 mt-5"><div class="media-stat"><div class="text-slate-400 text-xs">Total aktif</div><div class="text-2xl font-black">'.e($total).'</div></div><div class="media-stat"><div class="text-slate-400 text-xs">Folder</div><div class="font-bold">storage/media-library</div></div></div></section>';
    echo '<section><div class="admin-card p-4 mb-4"><form class="flex flex-col md:flex-row gap-3" method="get"><input class="admin-input" name="q" value="'.e($q).'" placeholder="Cari judul, file, alt, caption..."><button class="btn btn-success" type="submit">Cari</button><a class="btn btn-muted" href="'.admin_base('media-library').'">Reset</a></form></div>';
    if(!$media){ echo '<div class="admin-card p-6 text-slate-300">Belum ada media. Upload dulu dari form sebelah kiri.</div>'; }
    else{
        echo '<div class="media-grid">';
        foreach($media as $m){
            $url=pazar_file_url($m->m_file ?? '', 'pazar_media_library','m_file'); $isImg=pazar_is_image_path($m->m_file ?? ''); $size=(int)($m->m_size ?? 0); $sizeTxt=$size>0 ? number_format($size/1024,1,',','.').' KB' : '-';
            echo '<article class="media-card"><div class="media-card-preview">';
            if($isImg) echo '<img src="'.e($url).'" alt="'.e($m->m_alt_id ?: $m->m_title).'" onerror="this.style.display=\'none\';this.parentElement.innerHTML=\'<span class=&quot;text-slate-400&quot;>Preview tidak tersedia</span>\'">';
            else echo '<div class="text-center text-slate-300"><i data-lucide="file" class="w-10 h-10 mx-auto mb-2"></i><div>'.e(strtoupper(pathinfo($m->m_file ?? '', PATHINFO_EXTENSION))).'</div></div>';
            $imgHtml = '<img src="'.$url.'" alt="'.htmlspecialchars((string)($m->m_alt_id ?: $m->m_title), ENT_QUOTES, 'UTF-8').'">';
            echo '</div><div class="media-card-body"><h3 class="font-black line-clamp-2 mb-1">'.e($m->m_title ?: basename($m->m_file)).'</h3><div class="text-xs text-slate-400 mb-3">'.e(($m->m_width?($m->m_width.'×'.$m->m_height.' px · '):'').$sizeTxt).'</div><input class="copy-input mb-3" readonly value="'.e($url).'" onclick="this.select()"><div class="flex flex-wrap gap-2"><button type="button" class="btn btn-success" data-copy-text="'.e($url).'"><i data-lucide="copy" class="w-4 h-4"></i>Copy Link</button><button type="button" class="btn btn-muted" data-copy-text="'.e($imgHtml).'">Copy IMG</button><a class="btn btn-muted" target="_blank" href="'.e($url).'">Buka</a><a class="btn-danger text-sm mt-3" onclick="return confirm(\'Hapus media ini permanen? File gambar juga akan dihapus dari storage.\')" href="'.admin_base('media-library?delete='.$m->m_id).'">Hapus</a></div></div></article>';
        }
        echo '</div>';
    }
    echo '</section></div>';
    admin_shell_end();
}

function admin_profile(){
    pazar_bootstrap_v16();
    $current = $_SESSION['admin'] ?? null;
    if(!$current){ header('Location: '.admin_base('login')); exit; }
    $u = row('SELECT * FROM login_users WHERE u_id=?', [(int)($current->u_id ?? 0)]) ?: $current;
    if($_SERVER['REQUEST_METHOD']==='POST'){
        $name = trim($_POST['u_name'] ?? '');
        $email = strtolower(trim($_POST['u_email'] ?? ''));
        $currentPass = trim($_POST['current_password'] ?? '');
        $newPass = trim($_POST['new_password'] ?? '');
        $confirmPass = trim($_POST['confirm_password'] ?? '');
        $flashType = 'emerald';
        $messages = [];
        if($name==='') $messages[] = 'Nama wajib diisi.';
        if(!filter_var($email, FILTER_VALIDATE_EMAIL)) $messages[] = 'Email login tidak valid.';
        $emailExists = row('SELECT u_id FROM login_users WHERE u_email=? AND u_id<>? LIMIT 1', [$email,(int)$u->u_id]);
        if($emailExists) $messages[] = 'Email sudah dipakai user lain.';
        if($newPass!=='' || $confirmPass!=='' || $currentPass!==''){
            if($currentPass==='' || !password_verify($currentPass, (string)($u->u_password ?? ''))){ $messages[]='Password lama tidak sesuai.'; }
            if(strlen($newPass) < 6){ $messages[]='Password baru minimal 6 karakter.'; }
            if($newPass !== $confirmPass){ $messages[]='Konfirmasi password baru tidak sama.'; }
        }
        $profileImage = $u->u_profile_image ?? null;
        $uploaded = admin_save_uploaded_file('login_users','u_profile_image');
        if($uploaded !== null) $profileImage = $uploaded;
        if($messages){
            $flashType = 'rose';
            $_SESSION['translate_flash'] = implode(' ', $messages);
        } else {
            $sets=['u_name=?','u_email=?','u_profile_image=?','u_updated_at=NOW()'];
            $params=[$name,$email,$profileImage];
            if($newPass!==''){ $sets[]='u_password=?'; $params[]=password_hash($newPass, PASSWORD_DEFAULT); }
            $params[]=(int)$u->u_id;
            rows('UPDATE login_users SET '.implode(',',$sets).' WHERE u_id=?',$params);
            admin_log_activity('update','login_users',(int)$u->u_id,'self profile update');
            $_SESSION['admin'] = row('SELECT * FROM login_users WHERE u_id=?', [(int)$u->u_id]) ?: $u;
            $_SESSION['translate_flash'] = 'Profil berhasil diperbarui.'.($newPass!==''?' Password juga sudah diganti.':'');
        }
        header('Location: '.admin_base('profile')); exit;
    }
    admin_shell_start('My Profile');
    if(!empty($_SESSION['translate_flash'])){ $isErr=str_contains($_SESSION['translate_flash'],'wajib')||str_contains($_SESSION['translate_flash'],'tidak')||str_contains($_SESSION['translate_flash'],'dipakai')||str_contains($_SESSION['translate_flash'],'minimal'); echo '<div class="mb-5 p-4 rounded-xl border '.($isErr?'border-rose-700 bg-rose-950/40 text-rose-100':'border-emerald-700 bg-emerald-950/40 text-emerald-100').'">'.e($_SESSION['translate_flash']).'</div>'; unset($_SESSION['translate_flash']); }
    $avatar = storage_url($u->u_profile_image ?? '') ?: asset('img/Web/Logo.webp');
    $role = $u->u_role ?: 'admin';
    echo '<form method="post" enctype="multipart/form-data" class="max-w-6xl"><div class="profile-hero mb-6"><div class="flex flex-col md:flex-row gap-6 items-start md:items-center"><div class="shrink-0"><img id="profileAvatarPreview" class="profile-avatar" src="'.e($avatar).'" onerror="this.src=\''.asset('img/Web/Logo.webp').'\'" alt="Profile"><label class="btn btn-success mt-4 cursor-pointer justify-center w-full"><i data-lucide="camera" class="w-4 h-4"></i>Ganti Foto<input type="file" name="u_profile_image" class="hidden upload-input" data-preview="profileAvatarPreview" accept=".jpg,.jpeg,.png,.webp,.gif"></label></div><div class="flex-1"><h2 class="text-3xl font-black mb-2">'.e($u->u_name ?? 'Admin').'</h2><p class="text-slate-300 mb-4">Kelola profil akun sendiri, ganti foto, email login, dan password tanpa harus masuk ke Manage User.</p><div class="flex flex-wrap gap-2"><span class="badge">Role: '.e(ucwords(str_replace('_',' ',$role))).'</span><span class="badge">Status: '.(((int)($u->u_is_active ?? 0)===1)?'Aktif':'Nonaktif').'</span><span class="badge">Email: '.e($u->u_email ?? '-').'</span></div></div></div></div><div class="grid lg:grid-cols-2 gap-6"><div class="admin-card p-6"><div class="profile-section-title"><i data-lucide="user" class="w-5 h-5 text-emerald-300"></i>Data Akun</div><div class="space-y-4"><div><label class="admin-label">Nama Tampilan</label><input class="admin-input" name="u_name" value="'.e($u->u_name ?? '').'" required></div><div><label class="admin-label">Email Login</label><input type="email" class="admin-input" name="u_email" value="'.e($u->u_email ?? '').'" required><div class="admin-help">Email ini dipakai untuk login admin.</div></div><div class="profile-note">Foto profil tersimpan di folder storage. Gunakan JPG/PNG/WebP ukuran ringan supaya dashboard tetap cepat.</div></div></div><div class="admin-card p-6"><div class="profile-section-title"><i data-lucide="lock" class="w-5 h-5 text-emerald-300"></i>Ganti Password</div><div class="space-y-4"><div><label class="admin-label">Password Lama</label><input type="password" class="admin-input" name="current_password" autocomplete="current-password" placeholder="Isi hanya jika ingin mengganti password"></div><div><label class="admin-label">Password Baru</label><input type="password" class="admin-input" name="new_password" autocomplete="new-password" placeholder="Minimal 6 karakter"></div><div><label class="admin-label">Konfirmasi Password Baru</label><input type="password" class="admin-input" name="confirm_password" autocomplete="new-password" placeholder="Ulangi password baru"></div><div class="profile-note">Kosongkan semua kolom password jika hanya ingin mengganti nama, email, atau foto profil.</div></div></div></div><div class="admin-actions-sticky mt-6"><button class="btn btn-primary" type="submit"><i data-lucide="save" class="w-4 h-4"></i>Simpan Profil</button><a class="btn btn-muted" href="'.admin_base('dashboard').'">Kembali Dashboard</a></div></form>';
    admin_shell_end();
}

function admin(){
    $section = admin_current_section();
    if($section==='logout'){ session_destroy(); header('Location: '.admin_base('login')); exit; }
    if(empty($_SESSION['admin'])) admin_login();
    if($section==='' || $section==='login'){ header('Location: '.admin_base('dashboard')); exit; }
    if($section==='dashboard'){ admin_dashboard(); return; }
    if($section==='users'){ admin_manage_users(); return; }
    if($section==='media-library-json'){ admin_media_library_json(); return; }
    if($section==='media-library'){ admin_media_library(); return; }
    if($section==='cms-tools'){ header('Location: '.admin_base('dashboard')); exit; }
    if(str_starts_with($section,'manage')){ admin_manage(); return; }
    if($section==='profile'){ admin_profile(); return; }
    admin_dashboard();
}


function pazar_locale_switch_url($targetLoc, $sourcePath=null){
    $targetLoc = $targetLoc==='en' ? 'en' : 'id';
    if($sourcePath===null && !empty($GLOBALS['locale_switch_urls'][$targetLoc])) return $GLOBALS['locale_switch_urls'][$targetLoc];
    $path = $sourcePath!==null ? trim((string)$sourcePath,'/') : request_path_without_base();
    if(str_starts_with($path,'language/')){
        $ref=$_SERVER['HTTP_REFERER'] ?? '';
        if($ref){
            $rp=parse_url($ref, PHP_URL_PATH) ?: '';
            $base=parse_url(base_url(), PHP_URL_PATH) ?: '';
            $rp=trim($rp,'/'); $base=trim($base,'/');
            if($base!=='' && ($rp===$base || str_starts_with($rp,$base.'/'))) $rp=trim(substr($rp, strlen($base)),'/');
            if($rp!=='') $path=$rp;
        }
    }
    $parts = $path!=='' ? explode('/', trim($path,'/')) : [];
    $currentLoc = in_array($parts[0]??'', ['id','en'], true) ? $parts[0] : ($GLOBALS['locale']??'id');
    if(isset($parts[0]) && in_array($parts[0], ['id','en'], true)) $parts[0] = $targetLoc; else array_unshift($parts,$targetLoc);
    $map = [
        'id'=>[
            'perusahaan-kami'=>'our-company','brand-kami'=>'our-brand','produk'=>'products','resep'=>'recipes','karir'=>'career','lowongan'=>'vacancies','blog'=>'blog'
        ],
        'en'=>[
            'our-company'=>'perusahaan-kami','our-brand'=>'brand-kami','products'=>'produk','recipes'=>'resep','career'=>'karir','vacancies'=>'lowongan','blog'=>'blog',
            'product'=>'produk','recipe'=>'resep','vacancy'=>'lowongan'
        ]
    ];
    if(isset($parts[1])){
        if($targetLoc==='en' && isset($map['id'][$parts[1]])) $parts[1]=$map['id'][$parts[1]];
        elseif($targetLoc==='id' && isset($map['en'][$parts[1]])) $parts[1]=$map['en'][$parts[1]];
    }
    return base_url(implode('/', $parts));
}

function pazar_public_nav_html($active=''){
    $loc=$GLOBALS['locale']??'id';
    $activeClass='text-[#3fd144] font-extrabold';
    $normal='hover:text-[#3fd144] transition-colors';
    $cls=function($key) use ($active,$activeClass,$normal){ return ($active===$key?$activeClass:$normal); };
    $labelCompany=$loc==='en'?'Our Company':'Perusahaan Kami';
    $labelBrand=$loc==='en'?'Our Brand':'Brand Kami';
    $labelProducts=$loc==='en'?'Products':'Produk';
    $labelRecipes=$loc==='en'?'Recipes':'Resep';
    $labelCareer=$loc==='en'?'Career':'Karir';
    $labelCareerInfo=$loc==='en'?'Career Info':'Info Karir';
    $labelVacancies=$loc==='en'?'Vacancies':'Lowongan';
    $labelLang=$loc==='en'?'English (US)':'Indonesia';
    $labelTheme=(($_COOKIE['theme']??'light')==='dark')?($loc==='en'?'Switch to Light Mode':'Ganti ke Mode Terang'):($loc==='en'?'Switch to Dark Mode':'Ganti ke Mode Gelap');
    $flag=$loc==='en'?'img/Web/USA.svg':'img/Web/Indonesia.svg';
    $buyText=$loc==='en'?'Buy Now':'Beli Sekarang';
    $navClass='sticky top-0 z-30 bg-[#BF161C] text-white font-roboto shadow-[0_8px_24px_rgba(0,0,0,.12)]';
    $careerActive=in_array($active,['career','careerinfo','vacancies','vacancy'],true);
    $careerCls=$careerActive?$activeClass:$normal;
    $careerMenu='<div class="relative group"><button type="button" class="inline-flex items-center gap-1 '.$careerCls.'">'.$labelCareer.' <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg></button><div class="absolute left-0 hidden group-hover:block pt-3 z-50"><div class="w-44 rounded-xl bg-white text-slate-800 shadow-xl overflow-hidden"><a class="block px-4 py-3 hover:bg-[#3fd144] hover:text-white" href="'.route($loc.'.careerinfo').'">'.$labelCareerInfo.'</a><a class="block px-4 py-3 hover:bg-[#3fd144] hover:text-white" href="'.route($loc.'.vacancies').'">'.$labelVacancies.'</a></div></div></div>';
    $shopMenu='<div class="relative group w-full md1:w-auto"><button id="dropdownHoverButton" class="text-white bg-[#36b149] hover:bg-[#116a2a] focus:ring-4 focus:outline-none focus:bg-[#3fd144] font-medium rounded-lg text-sm px-5 py-2.5 text-center items-center justify-center min-w-[9rem] shadow-sm transition" type="button">'.$buyText.'</button><div class="absolute left-0 md1:left-auto md1:right-0 z-50 hidden group-hover:block bg-white divide-y divide-gray-100 rounded-lg shadow-xl w-full md1:w-44 overflow-hidden"><ul class="py-2 text-sm text-gray-700"><li><a href="https://shopee.co.id/pazar_seasonings" target="_blank" class="block px-4 py-2 hover:bg-[#3fd144] hover:text-white">Shopee</a></li><li><a href="https://www.tokopedia.com/pazarseasonings" target="_blank" class="block px-4 py-2 hover:bg-[#3fd144] hover:text-white">Tokopedia</a></li><li><a href="https://www.blibli.com/merchant/pazar-seasonings/PAS-70580" target="_blank" class="block px-4 py-2 hover:bg-[#3fd144] hover:text-white">Blibli</a></li><li><a href="https://www.lazada.co.id/shop/pazar-seasonings/" target="_blank" class="block px-4 py-2 hover:bg-[#3fd144] hover:text-white">Lazada</a></li><li><a href="https://www.tiktok.com/@pazar.seasonings" target="_blank" class="block px-4 py-2 hover:bg-[#3fd144] hover:text-white">Tiktok Shop</a></li></ul></div></div>';
    return '<nav class="'.$navClass.' public-pazar-nav"><div class="max-w-screen-xl mx-auto px-4 py-4 flex items-center justify-between gap-5"><a href="'.base_url($loc).'" class="shrink-0 public-pazar-logo-link"><img src="'.asset('img/Web/Logo.webp').'" class="public-pazar-logo h-12 md:h-14" alt="Pazar Logo"></a><div class="hidden lg:flex items-center justify-between gap-8 ml-auto"><div class="flex items-center gap-6 font-semibold whitespace-nowrap"><a class="'.$cls('company').'" href="'.route($loc.'.company').'">'.$labelCompany.'</a><a class="'.$cls('brand').'" href="'.route($loc.'.brand').'">'.$labelBrand.'</a><a class="'.$cls('products').'" href="'.route($loc.'.products').'">'.$labelProducts.'</a><a class="'.$cls('recipes').'" href="'.route($loc.'.recipes').'">'.$labelRecipes.'</a><a class="'.$cls('blog').'" href="'.route($loc.'.blogs').'">Blog</a>'.$careerMenu.'</div><div class="flex items-center gap-3 text-sm font-semibold shrink-0"><div class="relative group"><button type="button" title="'.$labelLang.'" aria-label="'.$labelLang.'" class="inline-flex h-10 w-10 items-center justify-center rounded-full border border-white/20 bg-white/5 hover:bg-white/15 transition"><img src="'.asset($flag).'" class="h-5 w-5 rounded-full object-cover" alt="Flag"></button><div class="absolute right-0 hidden group-hover:block pt-2 z-50"><div class="w-44 rounded-xl bg-white text-slate-800 shadow-xl overflow-hidden"><a class="flex items-center gap-2 px-4 py-3 hover:bg-emerald-50" href="'.pazar_locale_switch_url('id').'"><img src="'.asset('img/Web/Indonesia.svg').'" class="h-4 w-4 rounded-full" alt="Indonesia">Indonesia</a><a class="flex items-center gap-2 px-4 py-3 hover:bg-emerald-50" href="'.pazar_locale_switch_url('en').'"><img src="'.asset('img/Web/USA.svg').'" class="h-4 w-4 rounded-full" alt="English">English (US)</a></div></div></div><a title="'.$labelTheme.'" aria-label="'.$labelTheme.'" class="inline-flex h-10 w-10 items-center justify-center rounded-full border border-white/20 bg-white/5 hover:bg-white/15 transition" href="'.base_url('theme/toggle').'">'.((($_COOKIE['theme']??'light')==='dark')?'☀️':'🌙').'</a>'.$shopMenu.'</div></div></div></nav>';
}

function pazar_blog_nav_label(){ return ($GLOBALS['locale']??'id')==='en' ? 'Blog' : 'Blog'; }
function render_blog_list($blogs){
    $loc=$GLOBALS['locale']??'id'; $theme=$_COOKIE['theme']??'light'; $dark=$theme==='dark';
    $title=$loc==='en'?'Blog & Articles':'Blog & Artikel';
    $sub=$loc==='en'?'Cooking inspiration, product stories, practical tips, and flavorful ideas from Pazar Seasonings.':'Inspirasi masak, cerita produk, tips praktis, dan ide rasa dari Pazar Seasonings.';
    $read=$loc==='en'?'Read More':'Baca Selengkapnya';
    ob_start(); ?>
<!doctype html><html lang="<?=e($loc)?>" class="<?= $dark?'dark':'' ?>"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title><?=e($title)?> - Pazar Seasonings</title><link rel="icon" href="<?=asset('favicon.ico')?>"><link rel="shortcut icon" href="<?=asset('favicon.ico')?>"><link rel="apple-touch-icon" href="<?=asset('favicon.png')?>"><script src="https://cdn.tailwindcss.com"></script><link href="<?=asset('css/styles.css')?>" rel="stylesheet"><link href="https://fonts.cdnfonts.com/css/roboto" rel="stylesheet"><style>
body{font-family:'Roboto',Arial,sans-serif}.blog-hero{position:relative;overflow:hidden;background:#BF161C}.blog-hero:before{content:"";position:absolute;inset:0;background:linear-gradient(90deg,rgba(191,22,28,.96),rgba(191,22,28,.88)),url('<?=asset('img/Web/Header.webp')?>');background-size:cover;background-position:center;opacity:1}.blog-hero>*{position:relative}.blog-card{transition:.25s;box-shadow:0 18px 45px rgba(15,23,42,.08)}.blog-card:hover{transform:translateY(-6px);box-shadow:0 24px 60px rgba(15,23,42,.14)}.blog-card img{transition:.3s}.blog-card:hover img{transform:scale(1.055)}.blog-fallback{background:linear-gradient(135deg,#fff4f4,#fff),url('<?=asset('img/Web/Logo.webp')?>');background-repeat:no-repeat;background-position:center;background-size:120px auto}.line-clamp-2{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.line-clamp-3{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.blog-buy-chip{background:#36b149}.blog-section-title:after{content:"";display:block;width:72px;height:4px;background:#36b149;border-radius:999px;margin:14px auto 0}
</style></head><body class="<?= $dark?'bg-gray-900 text-gray-100':'bg-white text-gray-900' ?>"><?=pazar_public_nav_html('blog')?><header class="blog-hero text-white pt-16 pb-20"><div class="max-w-screen-xl mx-auto px-4 text-center"><div class="inline-flex items-center gap-2 rounded-full bg-white/10 border border-white/20 px-4 py-2 text-sm font-bold mb-5"><span class="h-2 w-2 rounded-full bg-[#3fd144]"></span>Pazar Seasonings</div><h1 class="text-4xl md:text-6xl font-extrabold mb-4 tracking-tight"><?=e($title)?></h1><p class="max-w-2xl mx-auto text-lg text-white/90 leading-relaxed"><?=e($sub)?></p></div></header><main class="max-w-screen-xl mx-auto px-4 py-14"><div class="text-center mb-10"><h2 class="blog-section-title text-3xl md:text-4xl font-extrabold"><?= $loc==='en'?'Latest Stories':'Artikel Terbaru' ?></h2><p class="mt-4 text-gray-500 max-w-2xl mx-auto"><?= $loc==='en'?'Explore recipes, product stories, and simple cooking ideas curated for everyday kitchens.':'Jelajahi resep, cerita produk, dan ide masak sederhana yang cocok untuk dapur sehari-hari.' ?></p></div><div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-8"><?php if($blogs): foreach($blogs as $b): $bt=$loc==='en'?(($b->b_title_en??'')?:($b->b_title_id??'')):($b->b_title_id??''); $ex=$loc==='en'?(($b->b_excerpt_en??'')?:($b->b_excerpt_id??'')):($b->b_excerpt_id??''); $cat=$loc==='en'?(($b->bc_title_en??'')?:($b->bc_title_id??'')):($b->bc_title_id??''); ?><article class="blog-card rounded-3xl overflow-hidden bg-white text-gray-900 border border-gray-100"><div class="h-56 overflow-hidden bg-gray-100 blog-fallback"><?php if(!empty($b->image_url)): ?><img src="<?=e($b->image_url)?>" class="w-full h-full object-cover" alt="<?=e($bt)?>" onerror="this.style.display='none';this.parentNode.classList.add('blog-fallback')"><?php endif; ?></div><div class="p-7"><div class="flex items-center gap-2 text-sm text-[#BF161C] font-extrabold mb-3"><span class="h-2 w-2 rounded-full bg-[#36b149]"></span><?=e($cat?:'Pazar')?></div><h2 class="text-2xl font-extrabold mb-3 line-clamp-2 leading-tight"><?=e($bt)?></h2><p class="text-gray-600 mb-6 line-clamp-3 leading-relaxed"><?=e(strip_tags($ex))?></p><a href="<?=route($loc.'.blog.show',$b->slug)?>" class="inline-flex items-center justify-center rounded-lg bg-[#36b149] hover:bg-[#116a2a] text-white font-bold px-5 py-2.5 transition shadow-sm"><?= $read ?> →</a></div></article><?php endforeach; else: ?><div class="col-span-full text-center py-20 text-gray-500"><?= $loc==='en'?'No articles yet.':'Belum ada artikel.' ?></div><?php endif; ?></div></main></body></html><?php return pazar_optimize_frontend_html(ob_get_clean());
}

function render_blog_detail($b,$blogs){
    $loc=$GLOBALS['locale']??'id'; $theme=$_COOKIE['theme']??'light'; $dark=$theme==='dark';
    $title=$loc==='en'?(($b->b_title_en??'')?:($b->b_title_id??'')):($b->b_title_id??'');
    $content=$loc==='en'?(($b->b_content_en??'')?:($b->b_content_id??'')):($b->b_content_id??'');
    $excerpt=$loc==='en'?(($b->b_excerpt_en??'')?:($b->b_excerpt_id??'')):($b->b_excerpt_id??'');
    $slugId = (($b->b_slug_id??'') ?: slugify($b->b_title_id??''));
    $slugEn = (($b->b_slug_en??'') ?: slugify(($b->b_title_en??'') ?: ($b->b_title_id??'')));
    $GLOBALS['locale_switch_urls'] = ['id'=>route('id.blog.show',$slugId), 'en'=>route('en.blog.show',$slugEn)];
    $currentUrl = ($loc==='en') ? route('en.blog.show',$slugEn) : route('id.blog.show',$slugId);
    $related=[]; foreach($blogs as $rb){ if((int)($rb->b_id??0)===(int)($b->b_id??0)) continue; if((string)($rb->b_category_id??'')===(string)($b->b_category_id??'')) $related[]=$rb; }
    if(count($related)<3){ foreach($blogs as $rb){ if((int)($rb->b_id??0)===(int)($b->b_id??0)) continue; if(!in_array($rb,$related,true)) $related[]=$rb; if(count($related)>=3) break; } }
    $related=array_slice($related,0,3);
    $comments=rows("SELECT * FROM pazar_blog_comment WHERE bcmt_blog_id=? AND bcmt_status='approved' ORDER BY bcmt_id DESC LIMIT 20", [(int)($b->b_id??0)]);
    $commentMsg='';
    if($_SERVER['REQUEST_METHOD']==='POST' && ($_POST['_blog_comment']??'')==='1'){
        $name=trim($_POST['comment_name']??''); $email=trim($_POST['comment_email']??''); $msg=trim($_POST['comment_message']??'');
        if($name!=='' && $msg!==''){
            rows("INSERT INTO pazar_blog_comment (bcmt_blog_id,bcmt_name,bcmt_email,bcmt_message,bcmt_status,bcmt_created_at) VALUES (?,?,?,?,?,NOW())", [(int)($b->b_id??0),$name,$email,$msg,'pending']); pazar_clear_frontend_cache();
            $commentMsg=$loc==='en'?'Thank you. Your comment is waiting for approval.':'Terima kasih. Komentar Anda menunggu persetujuan admin.';
        } else { $commentMsg=$loc==='en'?'Name and comment are required.':'Nama dan komentar wajib diisi.'; }
    }
    ob_start(); ?><!doctype html><html lang="<?=e($loc)?>" class="<?= $dark?'dark':'' ?>"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title><?=e($title)?> - Pazar Seasonings</title><meta name="description" content="<?=e(strip_tags($excerpt))?>"><link rel="icon" href="<?=asset('favicon.ico')?>"><link rel="shortcut icon" href="<?=asset('favicon.ico')?>"><link rel="apple-touch-icon" href="<?=asset('favicon.png')?>"><script src="https://cdn.tailwindcss.com"></script><link href="<?=asset('css/styles.css')?>" rel="stylesheet"><link href="https://fonts.cdnfonts.com/css/roboto" rel="stylesheet"><style>body{font-family:'Roboto',Arial,sans-serif}.article-hero{background:linear-gradient(90deg,rgba(191,22,28,.96),rgba(191,22,28,.88)),url('<?=asset('img/Web/Header.webp')?>');background-size:cover;background-position:center}.article-content h1{font-size:2.1rem;font-weight:900;margin:1.4rem 0 .8rem}.article-content h2{font-size:1.8rem;font-weight:800;margin:1.4rem 0 .7rem}.article-content h3{font-size:1.35rem;font-weight:800;margin:1.2rem 0 .6rem}.article-content p{margin:0 0 1rem;line-height:1.8}.article-content img{max-width:100%;height:auto;border-radius:16px;margin:1rem 0}.article-content iframe{width:100%;aspect-ratio:16/9;height:auto;border:0;border-radius:18px;display:block}.article-content ul{list-style:disc;margin-left:1.5rem}.article-content .pazar-media{display:block;margin:1.5rem 0}.article-content .pazar-media img{width:100%;height:auto;display:inline-block}.article-content .pazar-video{aspect-ratio:16/9;overflow:hidden;background:#111827;border-radius:18px;box-shadow:0 18px 40px rgba(15,23,42,.12)}.article-content .pazar-video iframe{width:100%;height:100%;border:0;border-radius:18px}.article-content .pazar-width-25{width:25%;max-width:100%}.article-content .pazar-width-50{width:50%;max-width:100%}.article-content .pazar-width-75{width:75%;max-width:100%}.article-content .pazar-width-full{width:100%;max-width:100%}.article-content .pazar-align-left{margin-right:auto;text-align:left}.article-content .pazar-align-center{margin-left:auto;margin-right:auto;text-align:center}.article-content .pazar-align-right{margin-left:auto;text-align:right}@media(max-width:768px){.article-content .pazar-width-25,.article-content .pazar-width-50,.article-content .pazar-width-75{width:100%}}.article-fallback{background:linear-gradient(135deg,#fff4f4,#fff),url('<?=asset('img/Web/Logo.webp')?>');background-repeat:no-repeat;background-position:center;background-size:140px auto}.social-share a{display:inline-flex;align-items:center;justify-content:center;border-radius:999px;padding:.65rem 1rem;font-weight:800;color:white}.comment-card,.related-card{box-shadow:0 14px 35px rgba(15,23,42,.08)}</style></head><body class="<?= $dark?'bg-gray-900 text-gray-100':'bg-white text-gray-900' ?>"><?=pazar_public_nav_html('blog')?><header class="article-hero text-white"><div class="max-w-4xl mx-auto px-4 py-16 text-center"><a class="inline-flex mb-6 text-sm font-bold text-white/90 hover:text-[#3fd144]" href="<?=route($loc.'.blogs')?>">← <?= $loc==='en'?'Back to Blog':'Kembali ke Blog' ?></a><h1 class="text-4xl md:text-5xl font-extrabold mb-5 leading-tight"><?=e($title)?></h1><p class="text-lg text-white/90 leading-relaxed"><?=e(strip_tags($excerpt))?></p></div></header><main class="max-w-4xl mx-auto px-4 py-12"><?php if(!empty($b->image_url)): ?><div class="article-fallback rounded-3xl shadow mb-10 overflow-hidden"><img src="<?=e($b->image_url)?>" class="w-full max-h-[460px] object-cover" alt="<?=e($title)?>" onerror="this.style.display=&quot;none&quot;"></div><?php endif; ?><article class="article-content prose max-w-none bg-white text-gray-900 rounded-3xl border border-gray-100 shadow-sm p-6 md:p-10"><?= $content ?></article><section class="mt-8 bg-white text-gray-900 rounded-3xl border border-gray-100 shadow-sm p-6 md:p-8"><h2 class="text-2xl font-black mb-4"><?= $loc==='en'?'Share this article':'Bagikan artikel ini' ?></h2><div class="social-share flex flex-wrap gap-3"><a style="background:#25D366" target="_blank" href="https://wa.me/?text=<?=rawurlencode($title.' '.$currentUrl)?>">WhatsApp</a><a style="background:#1877F2" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=<?=rawurlencode($currentUrl)?>">Facebook</a><a style="background:#111827" target="_blank" href="https://twitter.com/intent/tweet?url=<?=rawurlencode($currentUrl)?>&text=<?=rawurlencode($title)?>">X / Twitter</a><button type="button" class="rounded-full px-4 py-2 font-extrabold bg-gray-200 text-gray-900" onclick="navigator.clipboard&&navigator.clipboard.writeText('<?=e($currentUrl)?>');this.textContent='<?= $loc==='en'?'Copied':'Tersalin' ?> ✓';">Copy Link</button></div></section><section class="mt-8 bg-white text-gray-900 rounded-3xl border border-gray-100 shadow-sm p-6 md:p-8"><h2 class="text-2xl font-black mb-5"><?= $loc==='en'?'Comments':'Komentar' ?></h2><?php if($commentMsg): ?><div class="mb-5 rounded-xl bg-emerald-50 border border-emerald-200 text-emerald-900 p-4 font-bold"><?=e($commentMsg)?></div><?php endif; ?><form method="post" class="grid gap-4 mb-8"><input type="hidden" name="_blog_comment" value="1"><div class="grid md:grid-cols-2 gap-4"><input class="rounded-xl border border-gray-200 p-3" name="comment_name" placeholder="<?= $loc==='en'?'Your name':'Nama Anda' ?>" required><input class="rounded-xl border border-gray-200 p-3" type="email" name="comment_email" placeholder="Email (opsional)"></div><textarea class="rounded-xl border border-gray-200 p-3" name="comment_message" rows="4" placeholder="<?= $loc==='en'?'Write a comment...':'Tulis komentar...' ?>" required></textarea><button class="justify-self-start rounded-lg bg-[#36b149] hover:bg-[#116a2a] text-white font-black px-5 py-3" type="submit"><?= $loc==='en'?'Send Comment':'Kirim Komentar' ?></button><p class="text-sm text-gray-500"><?= $loc==='en'?'Comments are shown after admin approval.':'Komentar tampil setelah disetujui admin.' ?></p></form><div class="space-y-4"><?php if($comments): foreach($comments as $cm): ?><div class="comment-card rounded-2xl bg-gray-50 p-4"><div class="font-black"><?=e($cm->bcmt_name)?></div><div class="text-xs text-gray-500 mb-2"><?=e($cm->bcmt_created_at)?></div><p class="leading-relaxed"><?=nl2br(e($cm->bcmt_message))?></p></div><?php endforeach; else: ?><p class="text-gray-500"><?= $loc==='en'?'No comments yet. Be the first to comment.':'Belum ada komentar. Jadilah yang pertama berkomentar.' ?></p><?php endif; ?></div></section><?php if($related): ?><section class="mt-10"><h2 class="text-3xl font-black text-center mb-7"><?= $loc==='en'?'Related Posts':'Artikel Terkait' ?></h2><div class="grid md:grid-cols-3 gap-6"><?php foreach($related as $rb): $rt=$loc==='en'?(($rb->b_title_en??'')?:($rb->b_title_id??'')):($rb->b_title_id??''); $rex=$loc==='en'?(($rb->b_excerpt_en??'')?:($rb->b_excerpt_id??'')):($rb->b_excerpt_id??''); $rslug=$loc==='en'?(($rb->b_slug_en??'')?:slugify(($rb->b_title_en??'')?:($rb->b_title_id??''))):(($rb->b_slug_id??'')?:slugify($rb->b_title_id??'')); ?><a class="related-card block rounded-3xl overflow-hidden bg-white text-gray-900 border border-gray-100 hover:-translate-y-1 transition" href="<?=route($loc.'.blog.show',$rslug)?>"><div class="h-36 bg-gray-100 article-fallback overflow-hidden"><?php if(!empty($rb->image_url)): ?><img class="w-full h-full object-cover" src="<?=e($rb->image_url)?>" alt="<?=e($rt)?>" onerror="this.style.display='none'">
<?php endif; ?></div><div class="p-5"><h3 class="font-black leading-tight mb-2"><?=e($rt)?></h3><p class="text-sm text-gray-500 line-clamp-3"><?=e(strip_tags($rex))?></p></div></a><?php endforeach; ?></div></section><?php endif; ?></main></body></html><?php return pazar_optimize_frontend_html(ob_get_clean());
}


pazar_cache_try_serve();

$path = request_path_without_base();
if($path===special_admin_path() || str_starts_with($path, special_admin_path().'/') || $path==='admin-pazar-seasonings') admin();
if($path==='admin' || $path==='dashboard'){ header('Location: '.admin_base('dashboard')); exit; }
if($path==='theme/toggle'){ $new=($_COOKIE['theme']??'light')==='dark'?'light':'dark'; setcookie('theme',$new,time()+31536000,'/'); header('Location: '.($_SERVER['HTTP_REFERER']??base_url())); exit; }
if(str_starts_with($path,'language/')){ $l=basename($path); header('Location: '.pazar_locale_switch_url(($l==='en')?'en':'id')); exit; }
if($path===''){ header('Location: '.base_url('id')); exit; }
$parts=explode('/',$path); $GLOBALS['locale']=in_array($parts[0]??'id',['id','en'])?$parts[0]:'id'; $loc=$GLOBALS['locale']; $sub=$parts[1]??'';
$GLOBALS['routeName']=$loc.'.index';
if($sub===''){ viewPage('index','index'); }
if(in_array($sub,['perusahaan-kami','our-company'])){
    $GLOBALS['routeName']=$loc.'.company';
    $profiles=rows("SELECT * FROM pazar_company_profile ORDER BY cp_id");
    $by=[]; foreach($profiles as $cp){ $by[$cp->cp_type]=$cp; }
    $histories=rows("SELECT * FROM pazar_history ORDER BY hs_year");
    $has2024=false; foreach($histories as $h){ if((string)($h->hs_year ?? '')==='2024') $has2024=true; }
    if(!$has2024){ $h=(object)['hs_id'=>0,'hs_year'=>'2024','hs_description_id'=>'PT. Pristine Prima Lestari terus melangkah maju sebagai produsen pangan nasional yang terpercaya, inovatif, dan siap bersaing di pasar global.','hs_description_en'=>'PT. Pristine Prima Lestari continues to move forward as a trusted, innovative national food producer, ready to compete in the global market.','hs_image'=>'histories/1748230570_2022.webp']; $histories[]=$h; }
    usort($histories, fn($a,$b)=>strcmp((string)$a->hs_year,(string)$b->hs_year)); foreach($histories as $h) hydrate_images($h);
    viewPage('company','company',['companyWhat'=>$by['what']??null,'companyPolicy'=>$by['policy']??null,'companyVision'=>$by['vision']??null,'companyMission'=>$by['mission']??null,'histories'=>$histories]);
}
if(in_array($sub,['brand-kami','our-brand'])){
    $GLOBALS['routeName']=$loc.'.brand';
    $certifications=rows("SELECT * FROM pazar_certifications ORDER BY c_id"); foreach($certifications as $c) hydrate_images($c);
    $tests=rows("SELECT * FROM pazar_testimonial ORDER BY t_id"); foreach($tests as $t) hydrate_images($t);
    viewPage('brand','brand',['certifications'=>$certifications,'customerTestimonials'=>array_values(array_filter($tests,fn($x)=>strtolower($x->t_type??'')==='customer')),'chefTestimonials'=>array_values(array_filter($tests,fn($x)=>strtolower($x->t_type??'')==='chef'))]);
}
if(in_array($sub,['produk','products','product'])){
    $GLOBALS['routeName']=$loc.'.products';
    if(($parts[2]??'')==='unduh-katalog'||($parts[2]??'')==='download-catalog'){
        $cat=$loc==='en'?'Catalog PPL_ENG.pdf':'Catalog PPL _IDN.pdf'; header('Location: '.base_url('storage/catalogs/'.rawurlencode($cat))); exit;
    }
    $products=rows("SELECT p.*,pc.pc_title_id,pc.pc_title_en,pc.pc_image FROM pazar_product p LEFT JOIN pazar_product_category pc ON pc.pc_id=p.p_id_product_category WHERE p.p_is_active=1 ORDER BY p.p_id"); foreach($products as $p) normalize_product($p);
    $detailSlug = ($sub==='product') ? ($parts[2]??'') : (($sub==='produk' && !empty($parts[2]) && $parts[2]!=='unduh-katalog') ? $parts[2] : '');
    if($detailSlug){ foreach($products as $p){ if($p->slug===$detailSlug){ $GLOBALS['routeName']=$loc.'.product.show'; $GLOBALS['locale_switch_urls']=['id'=>route('id.product.show', (($p->p_slug_id??'') ?: slugify($p->p_title_id??''))), 'en'=>route('en.product.show', (($p->p_slug_en??'') ?: slugify(($p->p_title_en??'') ?: ($p->p_title_id??''))))]; viewPage('product-detail','products',['product'=>$p,'randomProducts'=>array_slice(array_values(array_filter($products,fn($x)=>$x->p_id!=$p->p_id)),0,4)]); } } }
    $categories=rows("SELECT * FROM pazar_product_category ORDER BY pc_id"); foreach($categories as $c) hydrate_images($c);
    viewPage('products','products',['products'=>$products,'categories'=>$categories]);
}
if(in_array($sub,['resep','recipes','recipe'])){
    $GLOBALS['routeName']=$loc.'.recipes';
    $recipes=rows("SELECT r.* FROM pazar_recipe r WHERE r.r_is_active=1 ORDER BY r.r_id"); foreach($recipes as $r) normalize_recipe($r);
    $detailSlug = ($sub==='recipe') ? ($parts[2]??'') : (($sub==='resep' && !empty($parts[2])) ? $parts[2] : '');
    if($detailSlug){ foreach($recipes as $r){ if($r->slug===$detailSlug){ $GLOBALS['routeName']=$loc.'.recipe.show'; $GLOBALS['locale_switch_urls']=['id'=>route('id.recipe.show', (($r->r_slug_id??'') ?: slugify($r->r_title_id??''))), 'en'=>route('en.recipe.show', (($r->r_slug_en??'') ?: slugify(($r->r_title_en??'') ?: ($r->r_title_id??''))))]; viewPage('recipe-detail','recipes',['recipe'=>$r,'randomRecipes'=>array_slice(array_values(array_filter($recipes,fn($x)=>$x->r_id!=$r->r_id)),0,3)]); } } }
    $categories=rows("SELECT * FROM pazar_recipe_category ORDER BY rc_id");
    viewPage('recipes','recipes',['recipes'=>$recipes,'categories'=>$categories,'recipeCategories'=>$categories]);
}

if(in_array($sub,['blog','artikel'])){
    pazar_bootstrap_v16();
    $GLOBALS['routeName']=$loc.'.blogs';
    $blogs=rows("SELECT b.*,bc.bc_title_id,bc.bc_title_en FROM pazar_blog b LEFT JOIN pazar_blog_category bc ON bc.bc_id=b.b_category_id WHERE b.b_is_active=1 AND b.b_status='published' AND (b.b_publish_at IS NULL OR b.b_publish_at <= NOW()) ORDER BY COALESCE(b.b_publish_at,b.b_created_at) DESC,b.b_id DESC");
    foreach($blogs as $b){ $b->slug=$loc==='en' ? (($b->b_slug_en??'') ?: slugify(($b->b_title_en??'') ?: ($b->b_title_id??''))) : (($b->b_slug_id??'') ?: slugify($b->b_title_id??'')); $b->image_url=pazar_file_url($b->b_image??'','pazar_blog','b_image'); }
    $detailSlug=$parts[2]??'';
    if($detailSlug){ foreach($blogs as $b){ if($b->slug===$detailSlug){ $GLOBALS['routeName']=$loc.'.blog.show'; echo render_blog_detail($b,$blogs); exit; } } }
    echo render_blog_list($blogs); exit;
}

if(in_array($sub,['info-karir','career-info'])){
    $GLOBALS['routeName']=$loc.'.careerinfo';
    $items=rows("SELECT * FROM career_work_at_pazar ORDER BY wap_id"); $w=[]; foreach($items as $it){$w[$it->wap_type]=$it;}
    $careerInfos=rows("SELECT * FROM career_careerinfo ORDER BY ci_id"); foreach($careerInfos as $ci) hydrate_images($ci);
    viewPage('careerinfo','careerinfo',['careerInfos'=>$careerInfos,'workAtPazarWork'=>$w['work']??null,'workAtPazarWhy'=>$w['why']??null,'workAtPazarJoin'=>$w['join']??null]);
}
if(in_array($sub,['lowongan','vacancies','vacancy'])){
    $GLOBALS['routeName']=$loc.'.vacancies';
    $vacancies=rows("SELECT v.*,d.da_title_id,d.da_title_en,e.ex_title_id,e.ex_title_en FROM career_vacancies v LEFT JOIN career_departments d ON d.da_id=v.v_department_id LEFT JOIN career_experiences e ON e.ex_id=v.v_experience_id WHERE v.v_is_active=1 ORDER BY v.v_id DESC"); foreach($vacancies as $v) normalize_vacancy($v);
    $detailSlug = ($sub==='vacancy') ? ($parts[2]??'') : (($sub==='lowongan' && !empty($parts[2])) ? $parts[2] : '');
    if($detailSlug){ foreach($vacancies as $v){ if($v->slug===$detailSlug){ $GLOBALS['routeName']=$loc.'.vacancy.show'; $GLOBALS['locale_switch_urls']=['id'=>route('id.vacancy.show', (($v->v_slug_id??'') ?: slugify($v->v_title_id??''))), 'en'=>route('en.vacancy.show', (($v->v_slug_en??'') ?: slugify(($v->v_title_en??'') ?: ($v->v_title_id??''))))]; viewPage('vacancy-detail','vacancies',['vacancy'=>$v,'relatedVacancies'=>array_slice(array_values(array_filter($vacancies,fn($x)=>$x->v_id!=$v->v_id)),0,3)]); } } }
    viewPage('vacancies','vacancies',['vacancies'=>$vacancies,'departments'=>rows("SELECT * FROM career_departments"),'experiences'=>rows("SELECT * FROM career_experiences")]);
}
http_response_code(404); echo render('404',pageData('index'));
